Compare commits

..

18 Commits

Author SHA1 Message Date
geky bot
4827795e4b Generated v1 prefixes 2019-04-08 23:29:26 +00:00
Christopher Haster
7e110b44c0 Added automatic version prefixing to releases
The script itself is a part of .travis.yml, using ./scripts/prefix.py
for applying prefixes to the source code.

This purpose of the automatic job is to provide a branch containing
version prefixes, to avoid name conflicts in binaries containing
different major versions of littlefs with only a git clone.

As a part of each release, two branches and a tag are created:
- vN        - moving branch
- vN-prefix - moving branch
- vN.N.N    - immutable tag

The major version branch (vM) is created on major releases, but updated
every patch release. The patch version tag (vM.M.P) is created every
patch release. Patch releases occur every time a commit is merged into
master, though multiple merges may be coalesced.

The major prefix branch (vM-prefix) is modified with the ./scripts/prefix.py
script. Note that this branch is updated as a synthetic merge commit
with the previous history of vM-prefix. The reason for this is to allow
users to easily update vM-prefix with a `git pull` as they would for
other branches.

A---B---C---D---E master, v1, v1.7.3
     \       \   \
      F-------G---H v1-prefix
2019-04-08 13:55:35 -05:00
Christopher Haster
7f7b7332e3 Added scripts/prefix.py for automatically prefixing version numbers
Example:
./scripts/prefix.py lfs2

Will convert the following:
lfs_* -> lfs2_*
LFS_* -> LFS2_*
-DLFS_* -> -DLFS2_*
2019-04-08 13:55:28 -05:00
Christopher Haster
d3a2cf48d4 Merge pull request #135 from johnlunney/patch-1
Add missing word (and reflow text)
2019-01-28 15:48:19 -06:00
johnl
22b0456623 Add missing word (and reflow text) 2019-01-26 21:38:23 +01:00
Christopher Haster
ec4d8b68ad Changed release script to generate drafts 2018-10-20 12:34:41 -05:00
Christopher Haster
c7894a61e1 Added a handful of links to related projects
Interesting open-source projects that I've ran into around embedded
storage. May be interesting to others in the embedded space.

Added mklfs, SPIFFS, and Dhara.

Also a thanks to jolivepetrus for posting the mklfs tool he put
together.
2018-10-20 12:34:41 -05:00
Christopher Haster
195075819e Added 2GiB file size limit and EFBIG reporting
On disk, littlefs uses 32-bit integers to track file size. This sets a
theoretical limit of 4GiB for files.

However, the API passes file sizes around as signed numbers, with
negative values representing error codes. This means that not all of the
APIs will work with file sizes > 2GiB.

Because of related complications over in FUSE land, I've added the LFS_FILE_MAX
constant and proper error reporting if file writes/seeks exceed the 2GiB limit.
In v2 this will join the other constants that get stored in the
superblock to help portability. Since littlefs is targeting
microcontrollers, it's likely this will be a sufficient solution.

Note that it's still possible to enable partial-support for 4GiB files
by defining LFS_FILE_MAX during compilation. This will work for most of
the APIs, except lfs_file_seek, lfs_file_tell, and lfs_file_size.

We can also consider improving support for 4GiB files, by making seek a
bit more complicated and adding a lfs_file_stat function. I'll leave
this for a future improvement if there's interest.

Found by cgrozemuller
2018-10-20 12:34:23 -05:00
Christopher Haster
97d8d5e96a Fixed issue where a rename causes a split and pushes dir out of sync
The issue happens when a rename causes a split in the destination pair.
If the destination pair is the same as the source pair, this triggers the
logic to keep both pairs in sync. Unfortunately, this logic didn't work,
because the source entry still resides in the old source pair, unlike
the destination pair, which is now in the new pair created by the split.

The best fix for now is to refetch the source pair after the changes to the
destination pair. This isn't the most efficient solution, but fortunately
this bug has already been fixed in the revamped move logic in littlefs v2
(currently in progress).

Found by ohoc
2018-10-20 12:34:11 -05:00
Christopher Haster
0bb1f7af17 Modified release script to create notes only on minor releases
Before, release notes with a list of changes were created every
patch release. Unfortunately, it looks like this will create a lot of
noise on github, with a notification every patch release, which may be
as often as every time a PR is merged.

Rather than creating all of this noise for relatively uninteresting
changes, the script will now stick to simple tags, and create the
release notes only on minor releases.

I think this is what several of you were originally suggesting,
sorry about the journey, at least I learned a lot.
2018-09-29 12:31:27 -05:00
Christopher Haster
447d89cbd8 Merge pull request #109 from OTAkeys/pr/fix-sign-compare
Fix -Wsign-compare error
2018-09-29 12:29:54 -05:00
Vincent Dupont
28d2d96a83 Fix -Wsign-compare error 2018-09-29 11:33:19 -05:00
Christopher Haster
cb62bf2188 Fixed release script issue with fetching recent tags
Fetching all tags was triggering the pagination system inside the github
API. This prevent version tags from being found.

Modified to use the version tag prefix in the ref lookup, however this
still may cause an issue if there are still enough patch releases to trigger
pagination.

Simpleish solution is to grab the link header to jump to the last page,
since pagination results appear to be in sorted order.
2018-09-27 14:46:12 -05:00
Christopher Haster
646b1b5a6c Added -Wjump-misses-init and fixed uninitialized warnings 2018-09-26 18:58:54 -05:00
Christopher Haster
1b7a15599e Merge pull request #106 from conkerkh/master
If stats file doesn't exist lfs_emubd_create will fail.
2018-09-26 18:58:34 -05:00
Christopher Haster
e5a6938faf Fixed possible infinite loop in deorphan step
Normally, the linked-list of directory pairs should terminate at a null
pointer. However, it is possible if the filesystem is corrupted, that
that this linked-list forms a cycle.

This should never happen with littlefs's power resilience, but if it does
we should recover appropriately.

Modified lfs_deorphan to notice if we have a cycle and return
LFS_ERR_CORRUPT in that situation.

Found by kneko715
2018-09-26 18:58:11 -05:00
Chris
6ad544f3f3 If stats file doesn't exist lfs_emubd_create will fail.
This will create default stats file if it doesn't exist.
2018-09-26 18:24:58 -05:00
Christopher Haster
3419284689 Fixed issue with corruption due to different cache sizes
The lfs_cache_zero function that was recently added assumed a single cache
size, which is incorrect. This would cause a buffer overflow if
read_size != prog_size.

Since lfs_cache_zero is only used for scrubbing prog caches, the fix
here is to use lfs_cache_drop instead on read caches. Info in read
caches should never make its way to disk.

Found by nstcl
2018-09-04 13:57:22 -05:00
32 changed files with 4701 additions and 7197 deletions

2
.gitignore vendored
View File

@@ -5,5 +5,5 @@
# Testing things # Testing things
blocks/ blocks/
lfs lfs1
test.c test.c

View File

@@ -18,17 +18,16 @@ script:
- make test QUIET=1 - make test QUIET=1
# 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+="-DLFS1_READ_SIZE=1 -DLFS1_PROG_SIZE=1"
- make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_CACHE_SIZE=512 -DLFS_BLOCK_CYCLES=16" - make test QUIET=1 CFLAGS+="-DLFS1_READ_SIZE=512 -DLFS1_PROG_SIZE=512"
- make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048" - make test QUIET=1 CFLAGS+="-DLFS1_BLOCK_COUNT=1023 -DLFS1_LOOKAHEAD=2048"
- make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0" - make clean test QUIET=1 CFLAGS+="-DLFS1_NO_INTRINSICS"
- make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS"
# 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 lfs1*.o | tr '\n' ' ')"
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR" CFLAGS+="-DLFS1_NO_ASSERT -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR"
| tee sizes | tee sizes
# update status if we succeeded, compare with master if possible # update status if we succeeded, compare with master if possible
@@ -36,7 +35,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" \
@@ -101,9 +100,10 @@ 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-alpha - git clone --depth 1 https://github.com/geky/littlefs-fuse
- fusermount -V - fusermount -V
- gcc --version - gcc --version
before_script: before_script:
@@ -119,8 +119,8 @@ jobs:
# self-host test # self-host test
- make -C littlefs-fuse - make -C littlefs-fuse
- littlefs-fuse/lfs --format /dev/loop0 - littlefs-fuse/lfs1 --format /dev/loop0
- littlefs-fuse/lfs /dev/loop0 mount - littlefs-fuse/lfs1 /dev/loop0 mount
- ls mount - ls mount
- mkdir mount/littlefs - mkdir mount/littlefs
@@ -129,56 +129,88 @@ jobs:
- ls - ls
- make -B test_dirs test_files QUIET=1 - make -B test_dirs test_files QUIET=1
# Automatically update releases # 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 lfs1.h
LFS1_VERSION=$(grep -ox '#define LFS1_VERSION .*' lfs1.h | cut -d ' ' -f3)
LFS1_VERSION_MAJOR=$((0xffff & ($LFS1_VERSION >> 16)))
LFS1_VERSION_MINOR=$((0xffff & ($LFS1_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$LFS1_VERSION_MAJOR.$LFS1_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)
LFS1_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
LFS1_VERSION="v$LFS1_VERSION_MAJOR.$LFS1_VERSION_MINOR.$LFS1_VERSION_PATCH"
echo "VERSION $LFS1_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')
if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0
# Create major branch
git branch v$LFS1_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$LFS1_VERSION_MAJOR-prefix || true
./scripts/prefix.py lfs1$LFS1_VERSION_MAJOR
git branch v$LFS1_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$LFS1_VERSION_MAJOR prefixes")
git reset --hard
# Update major version branches (vN and vN-prefix)
git push https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \
v$LFS1_VERSION_MAJOR \
v$LFS1_VERSION_MAJOR-prefix
# Create patch version tag (vN.N.N)
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs \
-d "{
\"ref\": \"refs/tags/$LFS1_VERSION\",
\"sha\": \"$TRAVIS_COMMIT\"
}"
# Create minor release?
[[ "$LFS1_VERSION" == *.0 ]] || exit 0
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*.0" | head -1)
if [ ! -z "$PREV" ]
then then
# Build release notes echo "PREV $PREV"
PREV=$(git tag --sort=-v:refname -l "v*" | head -1) CHANGES=$'### Changes\n\n'$( \
if [ ! -z "$PREV" ] git log --oneline $PREV.. --grep='^Merge' --invert-grep)
then printf "CHANGES\n%s\n\n" "$CHANGES"
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
# Create the release
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
-d "{
\"tag_name\": \"$LFS1_VERSION\",
\"name\": \"${LFS1_VERSION%.0}\",
\"draft\": true,
\"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\",
@@ -189,7 +221,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\",
@@ -200,7 +232,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\",

View File

@@ -1,6 +1,6 @@
TARGET = lfs.a TARGET = lfs1.a
ifneq ($(wildcard test.c main.c),) ifneq ($(wildcard test.c main.c),)
override TARGET = lfs override TARGET = lfs1
endif endif
CC ?= gcc CC ?= gcc
@@ -25,7 +25,8 @@ ifdef WORD
override CFLAGS += -m$(WORD) override CFLAGS += -m$(WORD)
endif endif
override CFLAGS += -I. override CFLAGS += -I.
override CFLAGS += -std=c99 -Wall -pedantic -Wshadow -Wunused-parameter override CFLAGS += -std=c99 -Wall -pedantic
override CFLAGS += -Wshadow -Wunused-parameter -Wjump-misses-init -Wsign-compare
all: $(TARGET) all: $(TARGET)
@@ -37,8 +38,7 @@ size: $(OBJ)
.SUFFIXES: .SUFFIXES:
test: test_format test_dirs test_files test_seek test_truncate \ test: test_format test_dirs test_files test_seek test_truncate \
test_entries test_interspersed test_alloc test_paths test_attrs \ test_interspersed test_alloc test_paths test_orphan test_move test_corrupt
test_move test_orphan test_corrupt
@rm test.c @rm test.c
test_%: tests/test_%.sh test_%: tests/test_%.sh
@@ -50,7 +50,7 @@ endif
-include $(DEP) -include $(DEP)
lfs: $(OBJ) lfs1: $(OBJ)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
%.a: $(OBJ) %.a: $(OBJ)

View File

@@ -30,14 +30,14 @@ main runs. The program can be interrupted at any time without losing track
of how many times it has been booted and without corrupting the filesystem: of how many times it has been booted and without corrupting the filesystem:
``` c ``` c
#include "lfs.h" #include "lfs1.h"
// variables used by the filesystem // variables used by the filesystem
lfs_t lfs; lfs1_t lfs1;
lfs_file_t file; lfs1_file_t file;
// configuration of the filesystem is provided by this struct // configuration of the filesystem is provided by this struct
const struct lfs_config cfg = { const struct lfs1_config cfg = {
// block device operations // block device operations
.read = user_provided_block_device_read, .read = user_provided_block_device_read,
.prog = user_provided_block_device_prog, .prog = user_provided_block_device_prog,
@@ -55,30 +55,30 @@ const struct lfs_config cfg = {
// entry point // entry point
int main(void) { int main(void) {
// mount the filesystem // mount the filesystem
int err = lfs_mount(&lfs, &cfg); int err = lfs1_mount(&lfs1, &cfg);
// reformat if we can't mount the filesystem // reformat if we can't mount the filesystem
// this should only happen on the first boot // this should only happen on the first boot
if (err) { if (err) {
lfs_format(&lfs, &cfg); lfs1_format(&lfs1, &cfg);
lfs_mount(&lfs, &cfg); lfs1_mount(&lfs1, &cfg);
} }
// read current count // read current count
uint32_t boot_count = 0; uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); lfs1_file_open(&lfs1, &file, "boot_count", LFS1_O_RDWR | LFS1_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); lfs1_file_read(&lfs1, &file, &boot_count, sizeof(boot_count));
// update boot count // update boot count
boot_count += 1; boot_count += 1;
lfs_file_rewind(&lfs, &file); lfs1_file_rewind(&lfs1, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count)); lfs1_file_write(&lfs1, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully // remember the storage is not updated until the file is closed successfully
lfs_file_close(&lfs, &file); lfs1_file_close(&lfs1, &file);
// release any resources we were using // release any resources we were using
lfs_unmount(&lfs); lfs1_unmount(&lfs1);
// print the boot count // print the boot count
printf("boot_count: %d\n", boot_count); printf("boot_count: %d\n", boot_count);
@@ -88,7 +88,7 @@ int main(void) {
## Usage ## Usage
Detailed documentation (or at least as much detail as is currently available) Detailed documentation (or at least as much detail as is currently available)
can be found in the comments in [lfs.h](lfs.h). can be found in the comments in [lfs1.h](lfs1.h).
As you may have noticed, littlefs takes in a configuration structure that As you may have noticed, littlefs takes in a configuration structure that
defines how the filesystem operates. The configuration struct provides the defines how the filesystem operates. The configuration struct provides the
@@ -96,9 +96,9 @@ filesystem with the block device operations and dimensions, tweakable
parameters that tradeoff memory usage for performance, and optional parameters that tradeoff memory usage for performance, and optional
static buffers if the user wants to avoid 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 `lfs1_t` type which is left up
to the user to allocate, allowing multiple filesystems to be in use to the user to allocate, allowing multiple filesystems to be in use
simultaneously. With the `lfs_t` and configuration struct, a user can simultaneously. With the `lfs1_t` and configuration struct, a user can
format a block device or mount the filesystem. format a block device or mount the filesystem.
Once mounted, the littlefs provides a full set of POSIX-like file and Once mounted, the littlefs provides a full set of POSIX-like file and
@@ -111,12 +111,12 @@ filesystem until sync or close is called on the file.
## Other notes ## Other notes
All littlefs have the potential to return a negative error code. The errors All littlefs calls have the potential to return a negative error code. The
can be either one of those found in the `enum lfs_error` in [lfs.h](lfs.h), errors can be either one of those found in the `enum lfs1_error` in
or an error returned by the user's block device operations. [lfs1.h](lfs1.h), or an error returned by the user's block device operations.
In the configuration struct, the `prog` and `erase` function provided by the In the configuration struct, the `prog` and `erase` function provided by the
user may return a `LFS_ERR_CORRUPT` error if the implementation already can user may return a `LFS1_ERR_CORRUPT` error if the implementation already can
detect corrupt blocks. However, the wear leveling does not depend on the return detect corrupt blocks. However, the wear leveling does not depend on the return
code of these functions, instead all data is read back and checked for code of these functions, instead all data is read back and checked for
integrity. integrity.
@@ -139,7 +139,7 @@ with all the nitty-gritty details. Can be useful for developing tooling.
## Testing ## Testing
The littlefs comes with a test suite designed to run on a PC using the The littlefs comes with a test suite designed to run on a PC using the
[emulated block device](emubd/lfs_emubd.h) found in the emubd directory. [emulated block device](emubd/lfs1_emubd.h) found in the emubd directory.
The tests assume a Linux environment and can be started with make: The tests assume a Linux environment and can be started with make:
``` bash ``` bash
@@ -175,3 +175,18 @@ handy.
[littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for [littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for
littlefs. I'm not sure why you would want this, but it is handy for demos. littlefs. I'm not sure why you would want this, but it is handy for demos.
You can see it in action [here](http://littlefs.geky.net/demo.html). You can see it in action [here](http://littlefs.geky.net/demo.html).
[mklfs](https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src) -
A command line tool built by the [Lua RTOS](https://github.com/whitecatboard/Lua-RTOS-ESP32)
guys for making littlefs images from a host PC. Supports Windows, Mac OS,
and Linux.
[SPIFFS](https://github.com/pellepl/spiffs) - Another excellent embedded
filesystem for NOR flash. As a more traditional logging filesystem with full
static wear-leveling, SPIFFS will likely outperform littlefs on small
memories such as the internal flash on microcontrollers.
[Dhara](https://github.com/dlbeer/dhara) - An interesting NAND flash
translation layer designed for small MCUs. It offers static wear-leveling and
power-resilience with only a fixed O(|address|) pointer structure stored on
each block and in RAM.

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "emubd/lfs_emubd.h" #include "emubd/lfs1_emubd.h"
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
@@ -19,43 +19,9 @@
#include <inttypes.h> #include <inttypes.h>
// Emulated block device utils
static inline void lfs_emubd_tole32(lfs_emubd_t *emu) {
emu->cfg.read_size = lfs_tole32(emu->cfg.read_size);
emu->cfg.prog_size = lfs_tole32(emu->cfg.prog_size);
emu->cfg.block_size = lfs_tole32(emu->cfg.block_size);
emu->cfg.block_count = lfs_tole32(emu->cfg.block_count);
emu->stats.read_count = lfs_tole32(emu->stats.read_count);
emu->stats.prog_count = lfs_tole32(emu->stats.prog_count);
emu->stats.erase_count = lfs_tole32(emu->stats.erase_count);
for (int i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]);
}
}
static inline void lfs_emubd_fromle32(lfs_emubd_t *emu) {
emu->cfg.read_size = lfs_fromle32(emu->cfg.read_size);
emu->cfg.prog_size = lfs_fromle32(emu->cfg.prog_size);
emu->cfg.block_size = lfs_fromle32(emu->cfg.block_size);
emu->cfg.block_count = lfs_fromle32(emu->cfg.block_count);
emu->stats.read_count = lfs_fromle32(emu->stats.read_count);
emu->stats.prog_count = lfs_fromle32(emu->stats.prog_count);
emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count);
for (int i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
}
}
// 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 lfs1_emubd_create(const struct lfs1_config *cfg, const char *path) {
lfs_emubd_t *emu = cfg->context; lfs1_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;
emu->cfg.block_size = cfg->block_size; emu->cfg.block_size = cfg->block_size;
@@ -63,7 +29,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
// Allocate buffer for creating children files // Allocate buffer for creating children files
size_t pathlen = strlen(path); size_t pathlen = strlen(path);
emu->path = malloc(pathlen + 1 + LFS_NAME_MAX + 1); emu->path = malloc(pathlen + 1 + LFS1_NAME_MAX + 1);
if (!emu->path) { if (!emu->path) {
return -ENOMEM; return -ENOMEM;
} }
@@ -71,7 +37,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
strcpy(emu->path, path); strcpy(emu->path, path);
emu->path[pathlen] = '/'; emu->path[pathlen] = '/';
emu->child = &emu->path[pathlen+1]; emu->child = &emu->path[pathlen+1];
memset(emu->child, '\0', LFS_NAME_MAX+1); memset(emu->child, '\0', LFS1_NAME_MAX+1);
// Create directory if it doesn't exist // Create directory if it doesn't exist
int err = mkdir(path, 0777); int err = mkdir(path, 0777);
@@ -80,31 +46,17 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
} }
// Load stats to continue incrementing // Load stats to continue incrementing
snprintf(emu->child, LFS_NAME_MAX, ".stats"); snprintf(emu->child, LFS1_NAME_MAX, "stats");
FILE *f = fopen(emu->path, "r");
if (!f) {
memset(&emu->stats, 0, sizeof(emu->stats));
} else {
size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
err = fclose(f); FILE *f = fopen(emu->path, "r");
if (err) { if (!f && errno != ENOENT) {
return -errno; return -errno;
}
} }
// Load history if (errno == ENOENT) {
snprintf(emu->child, LFS_NAME_MAX, ".history"); memset(&emu->stats, 0x0, sizeof(emu->stats));
f = fopen(emu->path, "r");
if (!f) {
memset(&emu->history, 0, sizeof(emu->history));
} else { } else {
size_t res = fread(&emu->history, sizeof(emu->history), 1, f); size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
return -errno; return -errno;
} }
@@ -118,16 +70,16 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
return 0; return 0;
} }
void lfs_emubd_destroy(const struct lfs_config *cfg) { void lfs1_emubd_destroy(const struct lfs1_config *cfg) {
lfs_emubd_sync(cfg); lfs1_emubd_sync(cfg);
lfs_emubd_t *emu = cfg->context; lfs1_emubd_t *emu = cfg->context;
free(emu->path); free(emu->path);
} }
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs1_emubd_read(const struct lfs1_config *cfg, lfs1_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) { lfs1_off_t off, void *buffer, lfs1_size_t size) {
lfs_emubd_t *emu = cfg->context; lfs1_emubd_t *emu = cfg->context;
uint8_t *data = buffer; uint8_t *data = buffer;
// Check if read is valid // Check if read is valid
@@ -139,7 +91,7 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
memset(data, 0, size); memset(data, 0, size);
// Read data // Read data
snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); snprintf(emu->child, LFS1_NAME_MAX, "%" PRIx32, block);
FILE *f = fopen(emu->path, "rb"); FILE *f = fopen(emu->path, "rb");
if (!f && errno != ENOENT) { if (!f && errno != ENOENT) {
@@ -167,9 +119,9 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
return 0; return 0;
} }
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs1_emubd_prog(const struct lfs1_config *cfg, lfs1_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs1_off_t off, const void *buffer, lfs1_size_t size) {
lfs_emubd_t *emu = cfg->context; lfs1_emubd_t *emu = cfg->context;
const uint8_t *data = buffer; const uint8_t *data = buffer;
// Check if write is valid // Check if write is valid
@@ -178,7 +130,7 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
assert(block < cfg->block_count); assert(block < cfg->block_count);
// Program data // Program data
snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); snprintf(emu->child, LFS1_NAME_MAX, "%" PRIx32, block);
FILE *f = fopen(emu->path, "r+b"); FILE *f = fopen(emu->path, "r+b");
if (!f) { if (!f) {
@@ -214,25 +166,18 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
return -errno; return -errno;
} }
// update history and stats
if (block != emu->history.blocks[0]) {
memcpy(&emu->history.blocks[1], &emu->history.blocks[0],
sizeof(emu->history) - sizeof(emu->history.blocks[0]));
emu->history.blocks[0] = block;
}
emu->stats.prog_count += 1; emu->stats.prog_count += 1;
return 0; return 0;
} }
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { int lfs1_emubd_erase(const struct lfs1_config *cfg, lfs1_block_t block) {
lfs_emubd_t *emu = cfg->context; lfs1_emubd_t *emu = cfg->context;
// Check if erase is valid // Check if erase is valid
assert(block < cfg->block_count); assert(block < cfg->block_count);
// Erase the block // Erase the block
snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); snprintf(emu->child, LFS1_NAME_MAX, "%" PRIx32, 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) {
@@ -262,19 +207,17 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
return 0; return 0;
} }
int lfs_emubd_sync(const struct lfs_config *cfg) { int lfs1_emubd_sync(const struct lfs1_config *cfg) {
lfs_emubd_t *emu = cfg->context; lfs1_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, LFS1_NAME_MAX, "config");
FILE *f = fopen(emu->path, "w"); FILE *f = fopen(emu->path, "w");
if (!f) { if (!f) {
return -errno; return -errno;
} }
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);
if (res < 1) { if (res < 1) {
return -errno; return -errno;
} }
@@ -284,33 +227,13 @@ int lfs_emubd_sync(const struct lfs_config *cfg) {
return -errno; return -errno;
} }
snprintf(emu->child, LFS_NAME_MAX, ".stats"); snprintf(emu->child, LFS1_NAME_MAX, "stats");
f = fopen(emu->path, "w"); f = fopen(emu->path, "w");
if (!f) { if (!f) {
return -errno; return -errno;
} }
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);
if (res < 1) {
return -errno;
}
err = fclose(f);
if (err) {
return -errno;
}
snprintf(emu->child, LFS_NAME_MAX, ".history");
f = fopen(emu->path, "w");
if (!f) {
return -errno;
}
lfs_emubd_tole32(emu);
res = fwrite(&emu->history, sizeof(emu->history), 1, f);
lfs_emubd_fromle32(emu);
if (res < 1) { if (res < 1) {
return -errno; return -errno;
} }

View File

@@ -4,11 +4,11 @@
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#ifndef LFS_EMUBD_H #ifndef LFS1_EMUBD_H
#define LFS_EMUBD_H #define LFS1_EMUBD_H
#include "lfs.h" #include "lfs1.h"
#include "lfs_util.h" #include "lfs1_util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
@@ -17,25 +17,25 @@ extern "C"
// Config options // Config options
#ifndef LFS_EMUBD_READ_SIZE #ifndef LFS1_EMUBD_READ_SIZE
#define LFS_EMUBD_READ_SIZE 1 #define LFS1_EMUBD_READ_SIZE 1
#endif #endif
#ifndef LFS_EMUBD_PROG_SIZE #ifndef LFS1_EMUBD_PROG_SIZE
#define LFS_EMUBD_PROG_SIZE 1 #define LFS1_EMUBD_PROG_SIZE 1
#endif #endif
#ifndef LFS_EMUBD_ERASE_SIZE #ifndef LFS1_EMUBD_ERASE_SIZE
#define LFS_EMUBD_ERASE_SIZE 512 #define LFS1_EMUBD_ERASE_SIZE 512
#endif #endif
#ifndef LFS_EMUBD_TOTAL_SIZE #ifndef LFS1_EMUBD_TOTAL_SIZE
#define LFS_EMUBD_TOTAL_SIZE 524288 #define LFS1_EMUBD_TOTAL_SIZE 524288
#endif #endif
// The emu bd state // The emu bd state
typedef struct lfs_emubd { typedef struct lfs1_emubd {
char *path; char *path;
char *child; char *child;
@@ -45,43 +45,39 @@ typedef struct lfs_emubd {
uint64_t erase_count; uint64_t erase_count;
} stats; } stats;
struct {
lfs_block_t blocks[4];
} history;
struct { struct {
uint32_t read_size; uint32_t read_size;
uint32_t prog_size; uint32_t prog_size;
uint32_t block_size; uint32_t block_size;
uint32_t block_count; uint32_t block_count;
} cfg; } cfg;
} lfs_emubd_t; } lfs1_emubd_t;
// Create a block device using path for the directory to store blocks // Create a block device using path for the directory to store blocks
int lfs_emubd_create(const struct lfs_config *cfg, const char *path); int lfs1_emubd_create(const struct lfs1_config *cfg, const char *path);
// Clean up memory associated with emu block device // Clean up memory associated with emu block device
void lfs_emubd_destroy(const struct lfs_config *cfg); void lfs1_emubd_destroy(const struct lfs1_config *cfg);
// Read a block // Read a block
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, int lfs1_emubd_read(const struct lfs1_config *cfg, lfs1_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size); lfs1_off_t off, void *buffer, lfs1_size_t size);
// Program a block // Program a block
// //
// The block must have previously been erased. // The block must have previously been erased.
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, int lfs1_emubd_prog(const struct lfs1_config *cfg, lfs1_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size); lfs1_off_t off, const void *buffer, lfs1_size_t size);
// Erase a block // Erase a block
// //
// A block must be erased before being programmed. The // A block must be erased before being programmed. The
// state of an erased block is undefined. // state of an erased block is undefined.
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block); int lfs1_emubd_erase(const struct lfs1_config *cfg, lfs1_block_t block);
// Sync the block device // Sync the block device
int lfs_emubd_sync(const struct lfs_config *cfg); int lfs1_emubd_sync(const struct lfs1_config *cfg);
#ifdef __cplusplus #ifdef __cplusplus

4173
lfs.c

File diff suppressed because it is too large Load Diff

639
lfs.h
View File

@@ -1,639 +0,0 @@
/*
* The little filesystem
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS_H
#define LFS_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
/// Version info ///
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00020000
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
// Version of On-disk data structures
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_DISK_VERSION 0x00020000
#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16))
#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0))
/// Definitions ///
// Type definitions
typedef uint32_t lfs_size_t;
typedef uint32_t lfs_off_t;
typedef int32_t lfs_ssize_t;
typedef int32_t lfs_soff_t;
typedef uint32_t lfs_block_t;
// Maximum size of all attributes per file in bytes, may be redefined but a
// a smaller LFS_ATTR_MAX has no benefit. Stored in 12-bits and limited
// to <= 0xfff. Stored in superblock and must be respected by other
// littlefs drivers.
#ifndef LFS_ATTR_MAX
#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
// Possible error codes, these are negative to allow
// valid positive return values
enum lfs_error {
LFS_ERR_OK = 0, // No error
LFS_ERR_IO = -5, // Error during device operation
LFS_ERR_CORRUPT = -84, // Corrupted
LFS_ERR_NOENT = -2, // No directory entry
LFS_ERR_EXIST = -17, // Entry already exists
LFS_ERR_NOTDIR = -20, // Entry is not a dir
LFS_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number
LFS_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NAMETOOLONG = -36, // File name too long
};
// File types
enum lfs_type {
// file types
LFS_TYPE_REG = 0x004,
LFS_TYPE_DIR = 0x005,
// internally used types
LFS_TYPE_USER = 0x100,
LFS_TYPE_SUPERBLOCK = 0x002,
LFS_TYPE_ROOT = 0x003,
LFS_TYPE_CHILD = 0x001,
LFS_TYPE_NAME = 0x000,
LFS_TYPE_DELETE = 0x060,
LFS_TYPE_STRUCT = 0x020,
LFS_TYPE_GLOBALS = 0x0e0,
LFS_TYPE_TAIL = 0x080,
LFS_TYPE_SOFTTAIL = 0x080,
LFS_TYPE_HARDTAIL = 0x081,
LFS_TYPE_CRC = 0x0a0,
LFS_TYPE_DIRSTRUCT = 0x020,
LFS_TYPE_INLINESTRUCT = 0x021,
LFS_TYPE_CTZSTRUCT = 0x022,
// internal chip sources
LFS_FROM_REGION = 0x000,
LFS_FROM_DISK = 0x200,
LFS_FROM_MOVE = 0x040,
LFS_FROM_COMPACT = 0x041,
LFS_FROM_SPLIT = 0x042,
LFS_FROM_ATTRS = 0x043,
};
// File open flags
enum lfs_open_flags {
// open flags
LFS_O_RDONLY = 1, // Open a file as read only
LFS_O_WRONLY = 2, // Open a file as write only
LFS_O_RDWR = 3, // Open a file as read and write
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
LFS_O_EXCL = 0x0200, // Fail if a file already exists
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS_O_APPEND = 0x0800, // Move to end of file on every write
// internally used flags
LFS_F_DIRTY = 0x010000, // File does not match storage
LFS_F_WRITING = 0x020000, // File has been written 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_INLINE = 0x100000, // Currently inlined in directory entry
};
// File seek flags
enum lfs_whence_flags {
LFS_SEEK_SET = 0, // Seek relative to an absolute position
LFS_SEEK_CUR = 1, // Seek relative to the current file position
LFS_SEEK_END = 2, // Seek relative to the end of the file
};
// Configuration provided during initialization of the littlefs
struct lfs_config {
// Opaque user provided context that can be used to pass
// information to the block device operations
void *context;
// Read a region in a block. Negative error codes are propogated
// to the user.
int (*read)(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a region in a block. The block must have previously
// been erased. Negative error codes are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*prog)(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propogated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
int (*erase)(const struct lfs_config *c, lfs_block_t block);
// Sync the state of the underlying block device. Negative error codes
// are propogated to the user.
int (*sync)(const struct lfs_config *c);
// Minimum size of a block read. All read operations will be a
// multiple of this value.
lfs_size_t read_size;
// Minimum size of a block program. All program operations will be a
// multiple of this value.
lfs_size_t prog_size;
// Size of an erasable block. This does not impact ram consumption and
// may be larger than the physical erase size. However, this should be
// kept small as each file currently takes up an entire block.
// Must be a multiple of the read, program, and cache sizes.
lfs_size_t block_size;
// Number of erasable blocks on the device.
lfs_size_t block_count;
// Number of erase cycles before we should move data to another block.
// May be zero to never move data, in which case no block-level
// wear-leveling is performed.
uint32_t block_cycles;
// Size of block caches. Each cache buffers a portion of a block in RAM.
// This determines the size of the read cache, the program cache, and a
// cache per file. Larger caches can improve performance by storing more
// data. Must be a multiple of the read and program sizes.
lfs_size_t cache_size;
// Number of blocks to lookahead during block allocation. A larger
// lookahead reduces the number of passes required to allocate a block.
// The lookahead buffer requires only 1 bit per block so it can be quite
// large with little ram impact. Should be a multiple of 32.
lfs_size_t lookahead;
// Optional, statically allocated read buffer. Must be read sized.
void *read_buffer;
// Optional, statically allocated program buffer. Must be program sized.
void *prog_buffer;
// Optional, statically allocated lookahead buffer. Must be 1 bit per
// lookahead block.
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
// 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
// superblock and must be respected by other littlefs drivers.
lfs_size_t name_max;
// Optional upper limit on inlined files in bytes. Large inline files
// require a larger cache size, but if a file can be inlined it does not
// need its own data block. Must be smaller than cache_size and less than
// LFS_INLINE_MAX. Defaults to min(LFS_INLINE_MAX, read_size) when zero.
// Stored in superblock and must be respected by other littlefs drivers.
lfs_size_t inline_max;
};
// File info structure
struct lfs_info {
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
uint8_t type;
// Size of the file, only valid for REG files
lfs_size_t size;
// Name of the file stored as a null-terminated string
char name[LFS_NAME_MAX+1];
};
// Custom attribute structure
struct lfs_attr {
// 8-bit type of attribute, provided by user and used to
// identify the attribute
uint8_t type;
// Pointer to buffer containing the attribute
void *buffer;
// Size of attribute in bytes, limited to LFS_ATTR_MAX
lfs_size_t size;
// Pointer to next attribute in linked list
struct lfs_attr *next;
};
// Optional configuration provided during lfs_file_opencfg
struct lfs_file_config {
// Optional, statically allocated buffer for files. Must be program sized.
// If NULL, malloc will be used by default.
void *buffer;
// Optional, linked list of custom attributes related to the file. If the
// 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
// attributes will be written to disk every file sync or close. This
// write occurs atomically with update to the file's contents.
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
// than the buffer, it will be padded with zeros. If the stored attribute
// is larger, then it will be silently truncated. If the attribute is not
// found, it will be created implicitly.
struct lfs_attr *attrs;
};
/// 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 {
lfs_block_t block;
lfs_off_t off;
lfs_size_t size;
uint8_t *buffer;
} lfs_cache_t;
typedef union lfs_global {
uint32_t u32[3];
struct {
lfs_block_t movepair[2];
uint16_t moveid;
uint8_t deorphaned;
} l;
struct {
lfs_block_t movepair[2];
uint16_t moveid;
uint8_t orphans;
} g;
} lfs_global_t;
typedef struct lfs_mdir {
lfs_block_t pair[2];
uint32_t rev;
uint32_t etag;
lfs_off_t off;
uint16_t count;
bool erased;
bool split;
lfs_block_t tail[2];
lfs_global_t locals;
} lfs_mdir_t;
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 {
struct lfs_dir *next;
uint16_t id;
uint8_t type;
lfs_mdir_t m;
lfs_off_t pos;
lfs_block_t head[2];
} lfs_dir_t;
typedef struct lfs_file {
struct lfs_file *next;
uint16_t id;
uint8_t type;
lfs_mdir_t m;
struct lfs_ctz {
lfs_block_t head;
lfs_size_t size;
} ctz;
uint32_t flags;
lfs_off_t pos;
lfs_block_t block;
lfs_off_t off;
lfs_cache_t cache;
const struct lfs_file_config *cfg;
} lfs_file_t;
typedef struct lfs_superblock {
char magic[8];
uint32_t version;
lfs_size_t block_size;
lfs_size_t block_count;
lfs_size_t attr_max;
lfs_size_t name_max;
lfs_size_t inline_max;
} lfs_superblock_t;
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 {
lfs_cache_t rcache;
lfs_cache_t pcache;
lfs_block_t root[2];
lfs_mlist_t *mlist;
uint32_t seed;
lfs_global_t globals;
lfs_global_t locals;
lfs_free_t free;
const struct lfs_config *cfg;
lfs_size_t block_size;
lfs_size_t block_count;
lfs_size_t attr_max;
lfs_size_t name_max;
lfs_size_t inline_max;
} lfs_t;
/// Filesystem functions ///
// Format a block device with the littlefs
//
// Requires a littlefs object and config struct. This clobbers the littlefs
// object, and does not leave the filesystem mounted. The config struct must
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs_format(lfs_t *lfs, const struct lfs_config *config);
// Mounts a littlefs
//
// Requires a littlefs object and config struct. Multiple filesystems
// may be mounted simultaneously with multiple littlefs objects. Both
// lfs and config must be allocated while mounted. The config struct must
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
// Unmounts a littlefs
//
// Does nothing besides releasing any allocated resources.
// Returns a negative error code on failure.
int lfs_unmount(lfs_t *lfs);
/// General operations ///
// Removes a file or directory
//
// If removing a directory, the directory must be empty.
// Returns a negative error code on failure.
int lfs_remove(lfs_t *lfs, const char *path);
// Rename or move a file or directory
//
// If the destination exists, it must match the source in type.
// If the destination is a directory, the directory must be empty.
//
// Returns a negative error code on failure.
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
// Find info about a file or directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a negative error code on failure.
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// Get a custom attribute
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
// the buffer, it will be padded with zeros. If the stored attribute is larger,
// then it will be silently truncated.
//
// 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_getattr(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size);
// Set custom attributes
//
// 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.
//
// Returns a negative error code on failure.
int lfs_setattr(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size);
/// File operations ///
// Open a file
//
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs_open_flags that are bitwise-ored together.
//
// Returns a negative error code on failure.
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags);
// Open a file with extra configuration
//
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs_open_flags that are bitwise-ored together.
//
// The config struct provides additional config options per file as described
// above. The config struct must be allocated while the file is open, and the
// config struct must be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags,
const struct lfs_file_config *config);
// Close a file
//
// Any pending writes are written out to storage as though
// sync had been called and releases any allocated resources.
//
// Returns a negative error code on failure.
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
// Synchronize a file on storage
//
// Any pending writes are written out to storage.
// Returns a negative error code on failure.
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
// Read data from file
//
// Takes a buffer and size indicating where to store the read data.
// Returns the number of bytes read, or a negative error code on failure.
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size);
// Write data to file
//
// Takes a buffer and size indicating the data to write. The file will not
// actually be updated on the storage until either sync or close is called.
//
// Returns the number of bytes written, or a negative error code on failure.
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size);
// Change the position of the file
//
// The change in position is determined by the offset and whence flag.
// 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 off, int whence);
// Truncates the size of the file to the specified size
//
// Returns a negative error code on failure.
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
// Return the position of the file
//
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
// Returns the position of the file, or a negative error code on failure.
lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
// Change the position of the file to the beginning of the file
//
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
// Returns a negative error code on failure.
int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
// Return the size of the file
//
// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
// Returns the size of the file, or a negative error code on failure.
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
/// Directory operations ///
// Create a directory
//
// Returns a negative error code on failure.
int lfs_mkdir(lfs_t *lfs, const char *path);
// Open a directory
//
// Once open a directory can be used with read to iterate over files.
// Returns a negative error code on failure.
int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
// Close a directory
//
// Releases any allocated resources.
// Returns a negative error code on failure.
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
// Read an entry in the directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a negative error code on failure.
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
// Change the position of the directory
//
// The new off must be a value previous returned from tell and specifies
// an absolute offset in the directory seek.
//
// Returns a negative error code on failure.
int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
// Return the position of the directory
//
// The returned offset is only meant to be consumed by seek and may not make
// sense, but does indicate the current position in the directory iteration.
//
// Returns the position of the directory, or a negative error code on failure.
lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
// Change the position of the directory to the beginning of the directory
//
// Returns a negative error code on failure.
int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
/// Filesystem-level filesystem operations
// Finds the current size of the filesystem
//
// Note: Result is best effort. If files share COW structures, the returned
// size may be larger than the filesystem actually is.
//
// Returns the number of allocated blocks, or a negative error code on failure.
lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// Traverse through all blocks in use by the filesystem
//
// The provided callback will be called with each block address that is
// currently in use by the filesystem. This can be used to determine which
// blocks are in use or how much of the storage is available.
//
// Returns a negative error code on failure.
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

2583
lfs1.c Normal file

File diff suppressed because it is too large Load Diff

501
lfs1.h Normal file
View File

@@ -0,0 +1,501 @@
/*
* The little filesystem
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS1_H
#define LFS1_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
/// Version info ///
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS1_VERSION 0x00010007
#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16))
#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0))
// Version of On-disk data structures
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS1_DISK_VERSION 0x00010001
#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16))
#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0))
/// Definitions ///
// Type definitions
typedef uint32_t lfs1_size_t;
typedef uint32_t lfs1_off_t;
typedef int32_t lfs1_ssize_t;
typedef int32_t lfs1_soff_t;
typedef uint32_t lfs1_block_t;
// Max name size in bytes
#ifndef LFS1_NAME_MAX
#define LFS1_NAME_MAX 255
#endif
// Max file size in bytes
#ifndef LFS1_FILE_MAX
#define LFS1_FILE_MAX 2147483647
#endif
// Possible error codes, these are negative to allow
// valid positive return values
enum lfs1_error {
LFS1_ERR_OK = 0, // No error
LFS1_ERR_IO = -5, // Error during device operation
LFS1_ERR_CORRUPT = -52, // Corrupted
LFS1_ERR_NOENT = -2, // No directory entry
LFS1_ERR_EXIST = -17, // Entry already exists
LFS1_ERR_NOTDIR = -20, // Entry is not a dir
LFS1_ERR_ISDIR = -21, // Entry is a dir
LFS1_ERR_NOTEMPTY = -39, // Dir is not empty
LFS1_ERR_BADF = -9, // Bad file number
LFS1_ERR_FBIG = -27, // File too large
LFS1_ERR_INVAL = -22, // Invalid parameter
LFS1_ERR_NOSPC = -28, // No space left on device
LFS1_ERR_NOMEM = -12, // No more memory available
};
// File types
enum lfs1_type {
LFS1_TYPE_REG = 0x11,
LFS1_TYPE_DIR = 0x22,
LFS1_TYPE_SUPERBLOCK = 0x2e,
};
// File open flags
enum lfs1_open_flags {
// open flags
LFS1_O_RDONLY = 1, // Open a file as read only
LFS1_O_WRONLY = 2, // Open a file as write only
LFS1_O_RDWR = 3, // Open a file as read and write
LFS1_O_CREAT = 0x0100, // Create a file if it does not exist
LFS1_O_EXCL = 0x0200, // Fail if a file already exists
LFS1_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS1_O_APPEND = 0x0800, // Move to end of file on every write
// internally used flags
LFS1_F_DIRTY = 0x10000, // File does not match storage
LFS1_F_WRITING = 0x20000, // File has been written since last flush
LFS1_F_READING = 0x40000, // File has been read since last flush
LFS1_F_ERRED = 0x80000, // An error occured during write
};
// File seek flags
enum lfs1_whence_flags {
LFS1_SEEK_SET = 0, // Seek relative to an absolute position
LFS1_SEEK_CUR = 1, // Seek relative to the current file position
LFS1_SEEK_END = 2, // Seek relative to the end of the file
};
// Configuration provided during initialization of the littlefs
struct lfs1_config {
// Opaque user provided context that can be used to pass
// information to the block device operations
void *context;
// Read a region in a block. Negative error codes are propogated
// to the user.
int (*read)(const struct lfs1_config *c, lfs1_block_t block,
lfs1_off_t off, void *buffer, lfs1_size_t size);
// Program a region in a block. The block must have previously
// been erased. Negative error codes are propogated to the user.
// May return LFS1_ERR_CORRUPT if the block should be considered bad.
int (*prog)(const struct lfs1_config *c, lfs1_block_t block,
lfs1_off_t off, const void *buffer, lfs1_size_t size);
// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propogated to the user.
// May return LFS1_ERR_CORRUPT if the block should be considered bad.
int (*erase)(const struct lfs1_config *c, lfs1_block_t block);
// Sync the state of the underlying block device. Negative error codes
// are propogated to the user.
int (*sync)(const struct lfs1_config *c);
// Minimum size of a block read. This determines the size of read buffers.
// This may be larger than the physical read size to improve performance
// by caching more of the block device.
lfs1_size_t read_size;
// Minimum size of a block program. This determines the size of program
// buffers. This may be larger than the physical program size to improve
// performance by caching more of the block device.
// Must be a multiple of the read size.
lfs1_size_t prog_size;
// Size of an erasable block. This does not impact ram consumption and
// may be larger than the physical erase size. However, this should be
// kept small as each file currently takes up an entire block.
// Must be a multiple of the program size.
lfs1_size_t block_size;
// Number of erasable blocks on the device.
lfs1_size_t block_count;
// Number of blocks to lookahead during block allocation. A larger
// lookahead reduces the number of passes required to allocate a block.
// The lookahead buffer requires only 1 bit per block so it can be quite
// large with little ram impact. Should be a multiple of 32.
lfs1_size_t lookahead;
// Optional, statically allocated read buffer. Must be read sized.
void *read_buffer;
// Optional, statically allocated program buffer. Must be program sized.
void *prog_buffer;
// Optional, statically allocated lookahead buffer. Must be 1 bit per
// lookahead block.
void *lookahead_buffer;
// Optional, statically allocated buffer for files. Must be program sized.
// If enabled, only one file may be opened at a time.
void *file_buffer;
};
// Optional configuration provided during lfs1_file_opencfg
struct lfs1_file_config {
// Optional, statically allocated buffer for files. Must be program sized.
// If NULL, malloc will be used by default.
void *buffer;
};
// File info structure
struct lfs1_info {
// Type of the file, either LFS1_TYPE_REG or LFS1_TYPE_DIR
uint8_t type;
// Size of the file, only valid for REG files
lfs1_size_t size;
// Name of the file stored as a null-terminated string
char name[LFS1_NAME_MAX+1];
};
/// littlefs data structures ///
typedef struct lfs1_entry {
lfs1_off_t off;
struct lfs1_disk_entry {
uint8_t type;
uint8_t elen;
uint8_t alen;
uint8_t nlen;
union {
struct {
lfs1_block_t head;
lfs1_size_t size;
} file;
lfs1_block_t dir[2];
} u;
} d;
} lfs1_entry_t;
typedef struct lfs1_cache {
lfs1_block_t block;
lfs1_off_t off;
uint8_t *buffer;
} lfs1_cache_t;
typedef struct lfs1_file {
struct lfs1_file *next;
lfs1_block_t pair[2];
lfs1_off_t poff;
lfs1_block_t head;
lfs1_size_t size;
const struct lfs1_file_config *cfg;
uint32_t flags;
lfs1_off_t pos;
lfs1_block_t block;
lfs1_off_t off;
lfs1_cache_t cache;
} lfs1_file_t;
typedef struct lfs1_dir {
struct lfs1_dir *next;
lfs1_block_t pair[2];
lfs1_off_t off;
lfs1_block_t head[2];
lfs1_off_t pos;
struct lfs1_disk_dir {
uint32_t rev;
lfs1_size_t size;
lfs1_block_t tail[2];
} d;
} lfs1_dir_t;
typedef struct lfs1_superblock {
lfs1_off_t off;
struct lfs1_disk_superblock {
uint8_t type;
uint8_t elen;
uint8_t alen;
uint8_t nlen;
lfs1_block_t root[2];
uint32_t block_size;
uint32_t block_count;
uint32_t version;
char magic[8];
} d;
} lfs1_superblock_t;
typedef struct lfs1_free {
lfs1_block_t off;
lfs1_block_t size;
lfs1_block_t i;
lfs1_block_t ack;
uint32_t *buffer;
} lfs1_free_t;
// The littlefs type
typedef struct lfs1 {
const struct lfs1_config *cfg;
lfs1_block_t root[2];
lfs1_file_t *files;
lfs1_dir_t *dirs;
lfs1_cache_t rcache;
lfs1_cache_t pcache;
lfs1_free_t free;
bool deorphaned;
bool moving;
} lfs1_t;
/// Filesystem functions ///
// Format a block device with the littlefs
//
// Requires a littlefs object and config struct. This clobbers the littlefs
// object, and does not leave the filesystem mounted. The config struct must
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *config);
// Mounts a littlefs
//
// Requires a littlefs object and config struct. Multiple filesystems
// may be mounted simultaneously with multiple littlefs objects. Both
// lfs1 and config must be allocated while mounted. The config struct must
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs1_mount(lfs1_t *lfs1, const struct lfs1_config *config);
// Unmounts a littlefs
//
// Does nothing besides releasing any allocated resources.
// Returns a negative error code on failure.
int lfs1_unmount(lfs1_t *lfs1);
/// General operations ///
// Removes a file or directory
//
// If removing a directory, the directory must be empty.
// Returns a negative error code on failure.
int lfs1_remove(lfs1_t *lfs1, const char *path);
// Rename or move a file or directory
//
// If the destination exists, it must match the source in type.
// If the destination is a directory, the directory must be empty.
//
// Returns a negative error code on failure.
int lfs1_rename(lfs1_t *lfs1, const char *oldpath, const char *newpath);
// Find info about a file or directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a negative error code on failure.
int lfs1_stat(lfs1_t *lfs1, const char *path, struct lfs1_info *info);
/// File operations ///
// Open a file
//
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs1_open_flags that are bitwise-ored together.
//
// Returns a negative error code on failure.
int lfs1_file_open(lfs1_t *lfs1, lfs1_file_t *file,
const char *path, int flags);
// Open a file with extra configuration
//
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs1_open_flags that are bitwise-ored together.
//
// The config struct provides additional config options per file as described
// above. The config struct must be allocated while the file is open, and the
// config struct must be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int lfs1_file_opencfg(lfs1_t *lfs1, lfs1_file_t *file,
const char *path, int flags,
const struct lfs1_file_config *config);
// Close a file
//
// Any pending writes are written out to storage as though
// sync had been called and releases any allocated resources.
//
// Returns a negative error code on failure.
int lfs1_file_close(lfs1_t *lfs1, lfs1_file_t *file);
// Synchronize a file on storage
//
// Any pending writes are written out to storage.
// Returns a negative error code on failure.
int lfs1_file_sync(lfs1_t *lfs1, lfs1_file_t *file);
// Read data from file
//
// Takes a buffer and size indicating where to store the read data.
// Returns the number of bytes read, or a negative error code on failure.
lfs1_ssize_t lfs1_file_read(lfs1_t *lfs1, lfs1_file_t *file,
void *buffer, lfs1_size_t size);
// Write data to file
//
// Takes a buffer and size indicating the data to write. The file will not
// actually be updated on the storage until either sync or close is called.
//
// Returns the number of bytes written, or a negative error code on failure.
lfs1_ssize_t lfs1_file_write(lfs1_t *lfs1, lfs1_file_t *file,
const void *buffer, lfs1_size_t size);
// Change the position of the file
//
// The change in position is determined by the offset and whence flag.
// Returns the old position of the file, or a negative error code on failure.
lfs1_soff_t lfs1_file_seek(lfs1_t *lfs1, lfs1_file_t *file,
lfs1_soff_t off, int whence);
// Truncates the size of the file to the specified size
//
// Returns a negative error code on failure.
int lfs1_file_truncate(lfs1_t *lfs1, lfs1_file_t *file, lfs1_off_t size);
// Return the position of the file
//
// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR)
// Returns the position of the file, or a negative error code on failure.
lfs1_soff_t lfs1_file_tell(lfs1_t *lfs1, lfs1_file_t *file);
// Change the position of the file to the beginning of the file
//
// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR)
// Returns a negative error code on failure.
int lfs1_file_rewind(lfs1_t *lfs1, lfs1_file_t *file);
// Return the size of the file
//
// Similar to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_END)
// Returns the size of the file, or a negative error code on failure.
lfs1_soff_t lfs1_file_size(lfs1_t *lfs1, lfs1_file_t *file);
/// Directory operations ///
// Create a directory
//
// Returns a negative error code on failure.
int lfs1_mkdir(lfs1_t *lfs1, const char *path);
// Open a directory
//
// Once open a directory can be used with read to iterate over files.
// Returns a negative error code on failure.
int lfs1_dir_open(lfs1_t *lfs1, lfs1_dir_t *dir, const char *path);
// Close a directory
//
// Releases any allocated resources.
// Returns a negative error code on failure.
int lfs1_dir_close(lfs1_t *lfs1, lfs1_dir_t *dir);
// Read an entry in the directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a negative error code on failure.
int lfs1_dir_read(lfs1_t *lfs1, lfs1_dir_t *dir, struct lfs1_info *info);
// Change the position of the directory
//
// The new off must be a value previous returned from tell and specifies
// an absolute offset in the directory seek.
//
// Returns a negative error code on failure.
int lfs1_dir_seek(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_off_t off);
// Return the position of the directory
//
// The returned offset is only meant to be consumed by seek and may not make
// sense, but does indicate the current position in the directory iteration.
//
// Returns the position of the directory, or a negative error code on failure.
lfs1_soff_t lfs1_dir_tell(lfs1_t *lfs1, lfs1_dir_t *dir);
// Change the position of the directory to the beginning of the directory
//
// Returns a negative error code on failure.
int lfs1_dir_rewind(lfs1_t *lfs1, lfs1_dir_t *dir);
/// Miscellaneous littlefs specific operations ///
// Traverse through all blocks in use by the filesystem
//
// The provided callback will be called with each block address that is
// currently in use by the filesystem. This can be used to determine which
// blocks are in use or how much of the storage is available.
//
// Returns a negative error code on failure.
int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data);
// Prunes any recoverable errors that may have occured in the filesystem
//
// Not needed to be called by user unless an operation is interrupted
// but the filesystem is still mounted. This is already called on first
// allocation.
//
// Returns a negative error code on failure.
int lfs1_deorphan(lfs1_t *lfs1);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -1,17 +1,17 @@
/* /*
* lfs util functions * lfs1 util functions
* *
* Copyright (c) 2017, Arm Limited. All rights reserved. * Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "lfs_util.h" #include "lfs1_util.h"
// Only compile if user does not provide custom config // Only compile if user does not provide custom config
#ifndef LFS_CONFIG #ifndef LFS1_CONFIG
// Software CRC implementation with small lookup table // Software CRC implementation with small lookup table
uint32_t lfs_crc32(uint32_t crc, const void *buffer, size_t size) { void lfs1_crc(uint32_t *restrict 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,
@@ -22,11 +22,9 @@ uint32_t lfs_crc32(uint32_t crc, const void *buffer, size_t size) {
const uint8_t *data = buffer; const uint8_t *data = buffer;
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; *crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
} }
return crc;
} }

186
lfs1_util.h Normal file
View File

@@ -0,0 +1,186 @@
/*
* lfs1 utility functions
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS1_UTIL_H
#define LFS1_UTIL_H
// Users can override lfs1_util.h with their own configuration by defining
// LFS1_CONFIG as a header file to include (-DLFS1_CONFIG=lfs1_config.h).
//
// If LFS1_CONFIG is used, none of the default utils will be emitted and must be
// provided by the config file. To start I would suggest copying lfs1_util.h and
// modifying as needed.
#ifdef LFS1_CONFIG
#define LFS1_STRINGIZE(x) LFS1_STRINGIZE2(x)
#define LFS1_STRINGIZE2(x) #x
#include LFS1_STRINGIZE(LFS1_CONFIG)
#else
// System includes
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#ifndef LFS1_NO_MALLOC
#include <stdlib.h>
#endif
#ifndef LFS1_NO_ASSERT
#include <assert.h>
#endif
#if !defined(LFS1_NO_DEBUG) || !defined(LFS1_NO_WARN) || !defined(LFS1_NO_ERROR)
#include <stdio.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
// Macros, may be replaced by system specific wrappers. Arguments to these
// macros must not have side-effects as the macros can be removed for a smaller
// code footprint
// Logging functions
#ifndef LFS1_NO_DEBUG
#define LFS1_DEBUG(fmt, ...) \
printf("lfs1 debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS1_DEBUG(fmt, ...)
#endif
#ifndef LFS1_NO_WARN
#define LFS1_WARN(fmt, ...) \
printf("lfs1 warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS1_WARN(fmt, ...)
#endif
#ifndef LFS1_NO_ERROR
#define LFS1_ERROR(fmt, ...) \
printf("lfs1 error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS1_ERROR(fmt, ...)
#endif
// Runtime assertions
#ifndef LFS1_NO_ASSERT
#define LFS1_ASSERT(test) assert(test)
#else
#define LFS1_ASSERT(test)
#endif
// Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS1_NO_INTRINSICS falls back to a more
// expensive basic C implementation for debugging purposes
// Min/max functions for unsigned 32-bit numbers
static inline uint32_t lfs1_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b;
}
static inline uint32_t lfs1_min(uint32_t a, uint32_t b) {
return (a < b) ? a : b;
}
// Find the next smallest power of 2 less than or equal to a
static inline uint32_t lfs1_npw2(uint32_t a) {
#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return 32 - __builtin_clz(a-1);
#else
uint32_t r = 0;
uint32_t s;
a -= 1;
s = (a > 0xffff) << 4; a >>= s; r |= s;
s = (a > 0xff ) << 3; a >>= s; r |= s;
s = (a > 0xf ) << 2; a >>= s; r |= s;
s = (a > 0x3 ) << 1; a >>= s; r |= s;
return (r | (a >> 1)) + 1;
#endif
}
// Count the number of trailing binary zeros in a
// lfs1_ctz(0) may be undefined
static inline uint32_t lfs1_ctz(uint32_t a) {
#if !defined(LFS1_NO_INTRINSICS) && defined(__GNUC__)
return __builtin_ctz(a);
#else
return lfs1_npw2((a & -a) + 1) - 1;
#endif
}
// Count the number of binary ones in a
static inline uint32_t lfs1_popc(uint32_t a) {
#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return __builtin_popcount(a);
#else
a = a - ((a >> 1) & 0x55555555);
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
#endif
}
// Find the sequence comparison of a and b, this is the distance
// between a and b ignoring overflow
static inline int lfs1_scmp(uint32_t a, uint32_t b) {
return (int)(unsigned)(a - b);
}
// Convert from 32-bit little-endian to native order
static inline uint32_t lfs1_fromle32(uint32_t a) {
#if !defined(LFS1_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
return a;
#elif !defined(LFS1_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_bswap32(a);
#else
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8) |
(((uint8_t*)&a)[2] << 16) |
(((uint8_t*)&a)[3] << 24);
#endif
}
// Convert to 32-bit little-endian from native order
static inline uint32_t lfs1_tole32(uint32_t a) {
return lfs1_fromle32(a);
}
// Calculate CRC-32 with polynomial = 0x04c11db7
void lfs1_crc(uint32_t *crc, const void *buffer, size_t size);
// Allocate memory, only used if buffers are not provided to littlefs
static inline void *lfs1_malloc(size_t size) {
#ifndef LFS1_NO_MALLOC
return malloc(size);
#else
(void)size;
return NULL;
#endif
}
// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs1_free(void *p) {
#ifndef LFS1_NO_MALLOC
free(p);
#else
(void)p;
#endif
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
#endif

View File

@@ -1,217 +0,0 @@
/*
* lfs utility functions
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS_UTIL_H
#define LFS_UTIL_H
// Users can override lfs_util.h with their own configuration by defining
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
//
// If LFS_CONFIG is used, none of the default utils will be emitted and must be
// provided by the config file. To start, I would suggest copying lfs_util.h
// and modifying as needed.
#ifdef LFS_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG)
#else
// System includes
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#ifndef LFS_NO_MALLOC
#include <stdlib.h>
#endif
#ifndef LFS_NO_ASSERT
#include <assert.h>
#endif
#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR)
#include <stdio.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
// Macros, may be replaced by system specific wrappers. Arguments to these
// macros must not have side-effects as the macros can be removed for a smaller
// code footprint
// Logging functions
#ifndef LFS_NO_DEBUG
#define LFS_DEBUG(fmt, ...) \
printf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS_DEBUG(fmt, ...)
#endif
#ifndef LFS_NO_WARN
#define LFS_WARN(fmt, ...) \
printf("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS_WARN(fmt, ...)
#endif
#ifndef LFS_NO_ERROR
#define LFS_ERROR(fmt, ...) \
printf("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS_ERROR(fmt, ...)
#endif
// Runtime assertions
#ifndef LFS_NO_ASSERT
#define LFS_ASSERT(test) assert(test)
#else
#define LFS_ASSERT(test)
#endif
// Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
// expensive basic C implementation for debugging purposes
// Min/max functions for unsigned 32-bit numbers
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b;
}
static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
return (a < b) ? a : b;
}
// Align to nearest multiple of a size
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
return a - (a % alignment);
}
static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
return lfs_aligndown(a + alignment-1, alignment);
}
// Find the next smallest power of 2 less than or equal to a
static inline uint32_t lfs_npw2(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return 32 - __builtin_clz(a-1);
#else
uint32_t r = 0;
uint32_t s;
a -= 1;
s = (a > 0xffff) << 4; a >>= s; r |= s;
s = (a > 0xff ) << 3; a >>= s; r |= s;
s = (a > 0xf ) << 2; a >>= s; r |= s;
s = (a > 0x3 ) << 1; a >>= s; r |= s;
return (r | (a >> 1)) + 1;
#endif
}
// Count the number of trailing binary zeros in a
// lfs_ctz(0) may be undefined
static inline uint32_t lfs_ctz(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
return __builtin_ctz(a);
#else
return lfs_npw2((a & -a) + 1) - 1;
#endif
}
// Count the number of binary ones in a
static inline uint32_t lfs_popc(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return __builtin_popcount(a);
#else
a = a - ((a >> 1) & 0x55555555);
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
#endif
}
// Find the sequence comparison of a and b, this is the distance
// between a and b ignoring overflow
static inline int lfs_scmp(uint32_t a, uint32_t b) {
return (int)(unsigned)(a - b);
}
// Convert between 32-bit little-endian and native order
static inline uint32_t lfs_fromle32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
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_bswap32(a);
#else
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8) |
(((uint8_t*)&a)[2] << 16) |
(((uint8_t*)&a)[3] << 24);
#endif
}
static inline uint32_t lfs_tole32(uint32_t a) {
return lfs_fromle32(a);
}
// Convert between 16-bit little-endian and native order
static inline uint16_t lfs_fromle16(uint16_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
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
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8);
#endif
}
static inline uint16_t lfs_tole16(uint16_t a) {
return lfs_fromle16(a);
}
// Calculate CRC-32 with polynomial = 0x04c11db7
uint32_t lfs_crc32(uint32_t crc, const void *buffer, size_t size);
// Allocate memory, only used if buffers are not provided to littlefs
static inline void *lfs_malloc(size_t size) {
#ifndef LFS_NO_MALLOC
return malloc(size);
#else
(void)size;
return NULL;
#endif
}
// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs_free(void *p) {
#ifndef LFS_NO_MALLOC
free(p);
#else
(void)p;
#endif
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
#endif

61
scripts/prefix.py Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python
# 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 lfs12
import os
import os.path
import re
import glob
import itertools
import tempfile
import shutil
import subprocess
DEFAULT_PREFIX = "lfs1"
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,43 +0,0 @@
#!/usr/bin/env python
import struct
import sys
import os
import argparse
def corrupt(block):
with open(block, 'r+b') as file:
# skip rev
file.read(4)
# go to last commit
tag = 0xffffffff
while True:
try:
ntag, = struct.unpack('<I', file.read(4))
except struct.error:
break
tag ^= ntag
file.seek(tag & 0xfff, os.SEEK_CUR)
# lob off last 3 bytes
file.seek(-((tag & 0xfff) + 3), os.SEEK_CUR)
file.truncate()
def main(args):
if args.n or not args.blocks:
with open('blocks/.history', 'rb') as file:
for i in range(int(args.n or 1)):
last, = struct.unpack('<I', file.read(4))
args.blocks.append('blocks/%x' % last)
for block in args.blocks:
print 'corrupting %s' % block
corrupt(block)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-n')
parser.add_argument('blocks', nargs='*')
main(parser.parse_args())

View File

@@ -1,107 +0,0 @@
#!/usr/bin/env python2
import struct
import binascii
TYPES = {
(0x1ff, 0x004): 'reg',
(0x1ff, 0x005): 'dir',
(0x1ff, 0x002): 'superblock',
(0x1ff, 0x003): 'root',
(0x1ff, 0x001): 'child',
(0x1ff, 0x060): 'delete',
(0x1f0, 0x0e0): 'globals',
(0x1ff, 0x080): 'tail soft',
(0x1ff, 0x081): 'tail hard',
(0x1f0, 0x0a0): 'crc',
(0x1ff, 0x020): 'struct dir',
(0x1ff, 0x021): 'struct inline',
(0x1ff, 0x022): '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, 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 %3s %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 & 0x7fc00000) >> 22
id = (tag & 0x003ff000) >> 12
size = (tag & 0x00000fff) >> 0
iscrc = (type & 0x1f0) == 0x0f0
data = file.read(size)
if iscrc:
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 iscrc 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 iscrc:
crc = 0
tag ^= (type & 1) << 31
return 0
if __name__ == "__main__":
import sys
sys.exit(main(*sys.argv[1:]))

View File

@@ -7,7 +7,7 @@ import os
import re import re
def main(): def main():
with open('blocks/.config') as file: with open('blocks/config') as file:
s = struct.unpack('<LLLL', file.read()) s = struct.unpack('<LLLL', file.read())
print 'read_size: %d' % s[0] print 'read_size: %d' % s[0]
print 'prog_size: %d' % s[1] print 'prog_size: %d' % s[1]
@@ -18,7 +18,7 @@ def main():
os.path.getsize(os.path.join('blocks', f)) os.path.getsize(os.path.join('blocks', f))
for f in os.listdir('blocks') if re.match('\d+', f)) for f in os.listdir('blocks') if re.match('\d+', f))
with open('blocks/.stats') as file: with open('blocks/stats') as file:
s = struct.unpack('<QQQ', file.read()) s = struct.unpack('<QQQ', file.read())
print 'read_count: %d' % s[0] print 'read_count: %d' % s[0]
print 'prog_count: %d' % s[1] print 'prog_count: %d' % s[1]

View File

@@ -1,6 +1,6 @@
/// AUTOGENERATED TEST /// /// AUTOGENERATED TEST ///
#include "lfs.h" #include "lfs1.h"
#include "emubd/lfs_emubd.h" #include "emubd/lfs1_emubd.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -37,7 +37,7 @@ static void test_assert(const char *file, unsigned line,
// 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, lfs1_block_t b) {{
(void)b; (void)b;
unsigned *u = (unsigned*)p; unsigned *u = (unsigned*)p;
*u += 1; *u += 1;
@@ -45,72 +45,62 @@ static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{
}} }}
// lfs declarations // lfs1 declarations
lfs_t lfs; lfs1_t lfs1;
lfs_emubd_t bd; lfs1_emubd_t bd;
lfs_file_t file[4]; lfs1_file_t file[4];
lfs_dir_t dir[4]; lfs1_dir_t dir[4];
struct lfs_info info; struct lfs1_info info;
uint8_t buffer[1024]; uint8_t buffer[1024];
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_size_t size; lfs1_size_t size;
lfs_size_t wsize; lfs1_size_t wsize;
lfs_size_t rsize; lfs1_size_t rsize;
uintmax_t test; uintmax_t test;
#ifndef LFS_READ_SIZE #ifndef LFS1_READ_SIZE
#define LFS_READ_SIZE 16 #define LFS1_READ_SIZE 16
#endif #endif
#ifndef LFS_PROG_SIZE #ifndef LFS1_PROG_SIZE
#define LFS_PROG_SIZE LFS_READ_SIZE #define LFS1_PROG_SIZE 16
#endif #endif
#ifndef LFS_BLOCK_SIZE #ifndef LFS1_BLOCK_SIZE
#define LFS_BLOCK_SIZE 512 #define LFS1_BLOCK_SIZE 512
#endif #endif
#ifndef LFS_BLOCK_COUNT #ifndef LFS1_BLOCK_COUNT
#define LFS_BLOCK_COUNT 1024 #define LFS1_BLOCK_COUNT 1024
#endif #endif
#ifndef LFS_BLOCK_CYCLES #ifndef LFS1_LOOKAHEAD
#define LFS_BLOCK_CYCLES 1024 #define LFS1_LOOKAHEAD 128
#endif #endif
#ifndef LFS_CACHE_SIZE const struct lfs1_config cfg = {{
#define LFS_CACHE_SIZE 64
#endif
#ifndef LFS_LOOKAHEAD
#define LFS_LOOKAHEAD 128
#endif
const struct lfs_config cfg = {{
.context = &bd, .context = &bd,
.read = &lfs_emubd_read, .read = &lfs1_emubd_read,
.prog = &lfs_emubd_prog, .prog = &lfs1_emubd_prog,
.erase = &lfs_emubd_erase, .erase = &lfs1_emubd_erase,
.sync = &lfs_emubd_sync, .sync = &lfs1_emubd_sync,
.read_size = LFS_READ_SIZE, .read_size = LFS1_READ_SIZE,
.prog_size = LFS_PROG_SIZE, .prog_size = LFS1_PROG_SIZE,
.block_size = LFS_BLOCK_SIZE, .block_size = LFS1_BLOCK_SIZE,
.block_count = LFS_BLOCK_COUNT, .block_count = LFS1_BLOCK_COUNT,
.block_cycles = LFS_BLOCK_CYCLES, .lookahead = LFS1_LOOKAHEAD,
.cache_size = LFS_CACHE_SIZE,
.lookahead = LFS_LOOKAHEAD,
}}; }};
// Entry point // Entry point
int main(void) {{ int main(void) {{
lfs_emubd_create(&cfg, "blocks"); lfs1_emubd_create(&cfg, "blocks");
{tests} {tests}
lfs_emubd_destroy(&cfg); lfs1_emubd_destroy(&cfg);
}} }}

View File

@@ -10,7 +10,7 @@ def generate(test):
template = file.read() template = file.read()
lines = [] lines = []
for line in re.split('(?<=(?:.;| [{}]))\n', test.read()): for line in re.split('(?<=[;{}])\n', test.read()):
match = re.match('(?: *\n)*( *)(.*)=>(.*);', line, re.DOTALL | re.MULTILINE) match = re.match('(?: *\n)*( *)(.*)=>(.*);', line, re.DOTALL | re.MULTILINE)
if match: if match:
tab, test, expect = match.groups() tab, test, expect = match.groups()
@@ -28,7 +28,7 @@ def generate(test):
# Remove build artifacts to force rebuild # Remove build artifacts to force rebuild
try: try:
os.remove('test.o') os.remove('test.o')
os.remove('lfs') os.remove('lfs1')
except OSError: except OSError:
pass pass
@@ -39,9 +39,9 @@ def compile():
def execute(): def execute():
if 'EXEC' in os.environ: if 'EXEC' in os.environ:
subprocess.check_call([os.environ['EXEC'], "./lfs"]) subprocess.check_call([os.environ['EXEC'], "./lfs1"])
else: else:
subprocess.check_call(["./lfs"]) subprocess.check_call(["./lfs1"])
def main(test=None): def main(test=None):
if test and not test.startswith('-'): if test and not test.startswith('-'):

View File

@@ -4,481 +4,424 @@ set -eu
echo "=== Allocator tests ===" echo "=== Allocator tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
SIZE=15000 SIZE=15000
lfs_mkdir() { lfs1_mkdir() {
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "$1") => 0; lfs1_mkdir(&lfs1, "$1") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
lfs_remove() { lfs1_remove() {
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_remove(&lfs, "$1/eggs") => 0; lfs1_remove(&lfs1, "$1/eggs") => 0;
lfs_remove(&lfs, "$1/bacon") => 0; lfs1_remove(&lfs1, "$1/bacon") => 0;
lfs_remove(&lfs, "$1/pancakes") => 0; lfs1_remove(&lfs1, "$1/pancakes") => 0;
lfs_remove(&lfs, "$1") => 0; lfs1_remove(&lfs1, "$1") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
lfs_alloc_singleproc() { lfs1_alloc_singleproc() {
tests/test.py << TEST tests/test.py << TEST
const char *names[] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
sprintf((char*)buffer, "$1/%s", names[n]); sprintf((char*)buffer, "$1/%s", names[n]);
lfs_file_open(&lfs, &file[n], (char*)buffer, lfs1_file_open(&lfs1, &file[n], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_APPEND) => 0;
} }
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
size = strlen(names[n]); size = strlen(names[n]);
for (int i = 0; i < $SIZE; i++) { for (int i = 0; i < $SIZE; i++) {
lfs_file_write(&lfs, &file[n], names[n], size) => size; lfs1_file_write(&lfs1, &file[n], names[n], size) => size;
} }
} }
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs_file_close(&lfs, &file[n]) => 0; lfs1_file_close(&lfs1, &file[n]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
lfs_alloc_multiproc() { lfs1_alloc_multiproc() {
for name in bacon eggs pancakes for name in bacon eggs pancakes
do do
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "$1/$name", lfs1_file_open(&lfs1, &file[0], "$1/$name",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_APPEND) => 0;
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[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
done done
} }
lfs_verify() { lfs1_verify() {
for name in bacon eggs pancakes for name in bacon eggs pancakes
do do
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "$1/$name", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "$1/$name", LFS1_O_RDONLY) => 0;
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[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "$name", size) => 0; memcmp(buffer, "$name", size) => 0;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
done done
} }
echo "--- Single-process allocation test ---" echo "--- Single-process allocation test ---"
lfs_mkdir singleproc lfs1_mkdir singleproc
lfs_alloc_singleproc singleproc lfs1_alloc_singleproc singleproc
lfs_verify singleproc lfs1_verify singleproc
echo "--- Multi-process allocation test ---" echo "--- Multi-process allocation test ---"
lfs_mkdir multiproc lfs1_mkdir multiproc
lfs_alloc_multiproc multiproc lfs1_alloc_multiproc multiproc
lfs_verify multiproc lfs1_verify multiproc
lfs_verify singleproc lfs1_verify singleproc
echo "--- Single-process reuse test ---" echo "--- Single-process reuse test ---"
lfs_remove singleproc lfs1_remove singleproc
lfs_mkdir singleprocreuse lfs1_mkdir singleprocreuse
lfs_alloc_singleproc singleprocreuse lfs1_alloc_singleproc singleprocreuse
lfs_verify singleprocreuse lfs1_verify singleprocreuse
lfs_verify multiproc lfs1_verify multiproc
echo "--- Multi-process reuse test ---" echo "--- Multi-process reuse test ---"
lfs_remove multiproc lfs1_remove multiproc
lfs_mkdir multiprocreuse lfs1_mkdir multiprocreuse
lfs_alloc_singleproc multiprocreuse lfs1_alloc_singleproc multiprocreuse
lfs_verify multiprocreuse lfs1_verify multiprocreuse
lfs_verify singleprocreuse lfs1_verify singleprocreuse
echo "--- Cleanup ---" echo "--- Cleanup ---"
lfs_remove multiprocreuse lfs1_remove multiprocreuse
lfs_remove singleprocreuse lfs1_remove singleprocreuse
echo "--- Exhaustion test ---" echo "--- Exhaustion test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT);
size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
lfs_file_sync(&lfs, &file[0]) => 0; lfs1_file_sync(&lfs1, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_ssize_t res; lfs1_ssize_t res;
while (true) { while (true) {
res = lfs_file_write(&lfs, &file[0], buffer, size); res = lfs1_file_write(&lfs1, &file[0], buffer, size);
if (res < 0) { if (res < 0) {
break; break;
} }
res => size; res => size;
} }
res => LFS_ERR_NOSPC; res => LFS1_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file[0]) => size; lfs1_file_size(&lfs1, &file[0]) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0; memcmp(buffer, "exhaustion", size) => 0;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Exhaustion wraparound test ---" echo "--- Exhaustion wraparound test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs1_remove(&lfs1, "exhaustion") => 0;
lfs_file_open(&lfs, &file[0], "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs1_file_open(&lfs1, &file[0], "padding", LFS1_O_WRONLY | LFS1_O_CREAT);
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[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_remove(&lfs, "padding") => 0; lfs1_remove(&lfs1, "padding") => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT);
size = strlen("exhaustion"); size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
lfs_file_sync(&lfs, &file[0]) => 0; lfs1_file_sync(&lfs1, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_ssize_t res; lfs1_ssize_t res;
while (true) { while (true) {
res = lfs_file_write(&lfs, &file[0], buffer, size); res = lfs1_file_write(&lfs1, &file[0], buffer, size);
if (res < 0) { if (res < 0) {
break; break;
} }
res => size; res => size;
} }
res => LFS_ERR_NOSPC; res => LFS1_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file[0]) => size; lfs1_file_size(&lfs1, &file[0]) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0; memcmp(buffer, "exhaustion", size) => 0;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs1_unmount(&lfs1) => 0;
lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Dir exhaustion test ---" echo "--- Dir exhaustion test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs1_remove(&lfs1, "exhaustion") => 0;
// find out max file size lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT);
lfs_mkdir(&lfs, "exhaustiondir") => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); for (lfs1_size_t i = 0;
int count = 0; i < (cfg.block_count-6)*(cfg.block_size-8);
int err; i += size) {
while (true) { lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
err = lfs_file_write(&lfs, &file[0], buffer, size);
if (err < 0) {
break;
}
count += 1;
} }
err => LFS_ERR_NOSPC; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0; lfs1_mkdir(&lfs1, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs1_remove(&lfs1, "exhaustiondir") => 0;
// see if dir fits with max file size lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_APPEND);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); size = strlen("blahblahblahblah");
for (int i = 0; i < count; i++) { memcpy(buffer, "blahblahblahblah", size);
lfs_file_write(&lfs, &file[0], buffer, size) => size; for (lfs1_size_t i = 0;
i < (cfg.block_size-8);
i += size) {
lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs1_mkdir(&lfs1, "exhaustiondir") => LFS1_ERR_NOSPC;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs1_unmount(&lfs1) => 0;
lfs_remove(&lfs, "exhaustion") => 0;
// see if dir fits with > max file size
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
for (int i = 0; i < count+1; i++) {
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs_file_close(&lfs, &file[0]) => 0;
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
lfs_remove(&lfs, "exhaustion") => 0;
lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Chained dir exhaustion test ---" echo "--- Chained dir exhaustion test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs1_remove(&lfs1, "exhaustion") => 0;
// find out max file size lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT);
lfs_mkdir(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 9; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, (char*)buffer) => 0;
}
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); for (lfs1_size_t i = 0;
int count = 0; i < (cfg.block_count-24)*(cfg.block_size-8);
int err; i += size) {
while (true) { lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
err = lfs_file_write(&lfs, &file[0], buffer, size);
if (err < 0) {
break;
}
count += 1;
} }
err => LFS_ERR_NOSPC; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 9; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_remove(&lfs, (char*)buffer) => 0;
}
// see that chained dir fails
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
for (int i = 0; i < count+1; i++) {
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs_file_sync(&lfs, &file[0]) => 0;
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, (char*)buffer) => 0; lfs1_mkdir(&lfs1, (char*)buffer) => 0;
} }
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; lfs1_mkdir(&lfs1, "exhaustiondir") => LFS1_ERR_NOSPC;
// shorten file to try a second chained dir lfs1_remove(&lfs1, "exhaustion") => 0;
while (true) { lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT);
err = lfs_mkdir(&lfs, "exhaustiondir"); size = strlen("blahblahblahblah");
if (err != LFS_ERR_NOSPC) { memcpy(buffer, "blahblahblahblah", size);
break; for (lfs1_size_t i = 0;
} i < (cfg.block_count-26)*(cfg.block_size-8);
i += size) {
lfs_ssize_t filesize = lfs_file_size(&lfs, &file[0]); lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
filesize > 0 => true;
lfs_file_truncate(&lfs, &file[0], filesize - size) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
} }
err => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; lfs1_mkdir(&lfs1, "exhaustiondir") => 0;
lfs1_mkdir(&lfs1, "exhaustiondir2") => LFS1_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Split dir test ---" echo "--- Split dir test ---"
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
// create one block hole for half a directory // create one block whole for half a directory
lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[0], "bump", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { lfs1_file_write(&lfs1, &file[0], (void*)"hi", 2) => 2;
memcpy(&buffer[i], "hi", 2); lfs1_file_close(&lfs1, &file[0]) => 0;
}
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => cfg.block_size;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT);
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8); i < (cfg.block_count-6)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &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; lfs1_remove(&lfs1, "bump") => 0;
lfs_mkdir(&lfs, "splitdir") => 0; lfs1_mkdir(&lfs1, "splitdir") => 0;
lfs_file_open(&lfs, &file[0], "splitdir/bump", lfs1_file_open(&lfs1, &file[0], "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { lfs1_file_write(&lfs1, &file[0], buffer, size) => LFS1_ERR_NOSPC;
memcpy(&buffer[i], "hi", 2); lfs1_file_close(&lfs1, &file[0]) => 0;
}
lfs_file_write(&lfs, &file[0], buffer, 2*cfg.block_size) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Outdated lookahead test ---" echo "--- Outdated lookahead test ---"
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file[0], "exhaustion1", lfs1_file_open(&lfs1, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-4)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion2", lfs1_file_open(&lfs1, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs1_mount(&lfs1, &cfg) => 0;
// rewrite one file // rewrite one file
lfs_file_open(&lfs, &file[0], "exhaustion1", lfs1_file_open(&lfs1, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS1_O_WRONLY | LFS1_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file[0]) => 0; lfs1_file_sync(&lfs1, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-4)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &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[0], "exhaustion2", lfs1_file_open(&lfs1, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS1_O_WRONLY | LFS1_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file[0]) => 0; lfs1_file_sync(&lfs1, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
TEST TEST
echo "--- Outdated lookahead and split dir test ---" echo "--- Outdated lookahead and split dir test ---"
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_open(&lfs, &file[0], "exhaustion1", lfs1_file_open(&lfs1, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg.block_count-4)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion2", lfs1_file_open(&lfs1, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs1_mount(&lfs1, &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[0], "exhaustion1", lfs1_file_open(&lfs1, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0; LFS1_O_WRONLY | LFS1_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file[0]) => 0; lfs1_file_sync(&lfs1, &file[0]) => 0;
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs1_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); i < ((cfg.block_count-4)/2 - 1)*(cfg.block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
// try to allocate a directory, should fail! // try to allocate a directory, should fail!
lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; lfs1_mkdir(&lfs1, "split") => LFS1_ERR_NOSPC;
// file should not fail // file should not fail
lfs_file_open(&lfs, &file[0], "notasplit", lfs1_file_open(&lfs1, &file[0], "notasplit",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], "hi", 2) => 2; lfs1_file_write(&lfs1, &file[0], "hi", 2) => 2;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -1,262 +0,0 @@
#!/bin/bash
set -eu
echo "=== Attr tests ==="
rm -rf blocks
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
lfs_file_open(&lfs, &file[0], "hello/hello",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], "hello", strlen("hello"))
=> strlen("hello");
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Set/get attribute ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'B', "", 0) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0;
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_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Set/get root attribute ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 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+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'B', "", 0) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0;
lfs_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+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Set/get file attribute ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
struct lfs_attr a1 = {'A', buffer, 4};
struct lfs_attr b1 = {'B', buffer+4, 6, &a1};
struct lfs_attr c1 = {'C', buffer+10, 5, &b1};
struct lfs_file_config cfg1 = {.attrs = &c1};
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer, "aaaa", 4);
memcpy(buffer+4, "bbbbbb", 6);
memcpy(buffer+10, "ccccc", 5);
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
b1.size = 0;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
b1.size = 6;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
b1.size = 6;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "dddddd", 6);
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
b1.size = 6;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
b1.size = 3;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "eee", 3);
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
b1.size = 6;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
a1.size = LFS_ATTR_MAX+1;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1)
=> LFS_ERR_NOSPC;
struct lfs_attr a2 = {'A', buffer, 4};
struct lfs_attr b2 = {'B', buffer+4, 9, &a2};
struct lfs_attr c2 = {'C', buffer+13, 5, &b2};
struct lfs_file_config cfg2 = {.attrs = &c2};
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDWR, &cfg2) => 0;
memcpy(buffer+4, "fffffffff", 9);
lfs_file_close(&lfs, &file[0]) => 0;
a1.size = 4;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
struct lfs_attr a2 = {'A', buffer, 4};
struct lfs_attr b2 = {'B', buffer+4, 9, &a2};
struct lfs_attr c2 = {'C', buffer+13, 5, &b2};
struct lfs_file_config cfg2 = {.attrs = &c2};
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Deferred file attributes ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
struct lfs_attr a1 = {'B', "gggg", 4};
struct lfs_attr b1 = {'C', "", 0, &a1};
struct lfs_attr c1 = {'D', "hhhh", 4, &b1};
struct lfs_file_config cfg1 = {.attrs = &c1};
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", 'C', buffer+9, 9) => 5;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 0;
memcmp(buffer, "fffffffff", 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;
lfs_file_sync(&lfs, &file[0]) => 0;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4;
memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0;
memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0;
memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"
tests/stats.py

View File

@@ -6,113 +6,112 @@ echo "=== Corrupt tests ==="
NAMEMULT=64 NAMEMULT=64
FILEMULT=1 FILEMULT=1
lfs_mktree() { lfs1_mktree() {
tests/test.py ${1:-} << TEST tests/test.py ${1:-} << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < $NAMEMULT; j++) { for (int j = 0; j < $NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
buffer[$NAMEMULT] = '\0'; buffer[$NAMEMULT] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => 0; lfs1_mkdir(&lfs1, (char*)buffer) => 0;
buffer[$NAMEMULT] = '/'; buffer[$NAMEMULT] = '/';
for (int j = 0; j < $NAMEMULT; j++) { for (int j = 0; j < $NAMEMULT; j++) {
buffer[j+$NAMEMULT+1] = '0'+i; buffer[j+$NAMEMULT+1] = '0'+i;
} }
buffer[2*$NAMEMULT+1] = '\0'; buffer[2*$NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file[0], (char*)buffer, lfs1_file_open(&lfs1, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = $NAMEMULT; size = $NAMEMULT;
for (int j = 0; j < i*$FILEMULT; j++) { for (int j = 0; j < i*$FILEMULT; j++) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
lfs_chktree() { lfs1_chktree() {
tests/test.py ${1:-} << TEST tests/test.py ${1:-} << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
for (int j = 0; j < $NAMEMULT; j++) { for (int j = 0; j < $NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
buffer[$NAMEMULT] = '\0'; buffer[$NAMEMULT] = '\0';
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs1_stat(&lfs1, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
buffer[$NAMEMULT] = '/'; buffer[$NAMEMULT] = '/';
for (int j = 0; j < $NAMEMULT; j++) { for (int j = 0; j < $NAMEMULT; j++) {
buffer[j+$NAMEMULT+1] = '0'+i; buffer[j+$NAMEMULT+1] = '0'+i;
} }
buffer[2*$NAMEMULT+1] = '\0'; buffer[2*$NAMEMULT+1] = '\0';
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], (char*)buffer, LFS1_O_RDONLY) => 0;
size = $NAMEMULT; size = $NAMEMULT;
for (int j = 0; j < i*$FILEMULT; j++) { for (int j = 0; j < i*$FILEMULT; j++) {
lfs_file_read(&lfs, &file[0], rbuffer, size) => size; lfs1_file_read(&lfs1, &file[0], rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0; memcmp(buffer, rbuffer, size) => 0;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
echo "--- Sanity check ---" echo "--- Sanity check ---"
rm -rf blocks rm -rf blocks
lfs_mktree lfs1_mktree
lfs_chktree lfs1_chktree
BLOCKS="$(ls blocks | grep -vw '[01]')"
echo "--- Block corruption ---" echo "--- Block corruption ---"
for b in $BLOCKS for i in {0..33}
do do
rm -rf blocks rm -rf blocks
mkdir blocks mkdir blocks
ln -s /dev/zero blocks/$b ln -s /dev/zero blocks/$(printf '%x' $i)
lfs_mktree lfs1_mktree
lfs_chktree lfs1_chktree
done done
echo "--- Block persistance ---" echo "--- Block persistance ---"
for b in $BLOCKS for i in {0..33}
do do
rm -rf blocks rm -rf blocks
mkdir blocks mkdir blocks
lfs_mktree lfs1_mktree
chmod a-w blocks/$b chmod a-w blocks/$(printf '%x' $i)
lfs_mktree lfs1_mktree
lfs_chktree lfs1_chktree
done done
echo "--- Big region corruption ---" echo "--- Big region corruption ---"
rm -rf blocks rm -rf blocks
mkdir blocks mkdir blocks
for i in {2..512} for i in {2..255}
do do
ln -s /dev/zero blocks/$(printf '%x' $i) ln -s /dev/zero blocks/$(printf '%x' $i)
done done
lfs_mktree lfs1_mktree
lfs_chktree lfs1_chktree
echo "--- Alternating corruption ---" echo "--- Alternating corruption ---"
rm -rf blocks rm -rf blocks
mkdir blocks mkdir blocks
for i in {2..1024..2} for i in {2..511..2}
do do
ln -s /dev/zero blocks/$(printf '%x' $i) ln -s /dev/zero blocks/$(printf '%x' $i)
done done
lfs_mktree lfs1_mktree
lfs_chktree lfs1_chktree
echo "--- Results ---" echo "--- Results ---"
tests/stats.py tests/stats.py

View File

@@ -6,294 +6,294 @@ LARGESIZE=128
echo "=== Directory tests ===" echo "=== Directory tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
echo "--- Root directory ---" echo "--- Root directory ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Directory creation ---" echo "--- Directory creation ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0; lfs1_mkdir(&lfs1, "potato") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- File creation ---" echo "--- File creation ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs1_file_open(&lfs1, &file[0], "burito", LFS1_O_CREAT | LFS1_O_WRONLY) => 0;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Directory iteration ---" echo "--- Directory iteration ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "potato") => 0; strcmp(info.name, "potato") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Directory failures ---" echo "--- Directory failures ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; lfs1_mkdir(&lfs1, "potato") => LFS1_ERR_EXIST;
lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "tomato") => LFS1_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERR_NOTDIR; lfs1_dir_open(&lfs1, &dir[0], "burito") => LFS1_ERR_NOTDIR;
lfs_file_open(&lfs, &file[0], "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs1_file_open(&lfs1, &file[0], "tomato", LFS1_O_RDONLY) => LFS1_ERR_NOENT;
lfs_file_open(&lfs, &file[0], "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; lfs1_file_open(&lfs1, &file[0], "potato", LFS1_O_RDONLY) => LFS1_ERR_ISDIR;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Nested directories ---" echo "--- Nested directories ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "potato/baked") => 0; lfs1_mkdir(&lfs1, "potato/baked") => 0;
lfs_mkdir(&lfs, "potato/sweet") => 0; lfs1_mkdir(&lfs1, "potato/sweet") => 0;
lfs_mkdir(&lfs, "potato/fried") => 0; lfs1_mkdir(&lfs1, "potato/fried") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "potato") => 0; lfs1_dir_open(&lfs1, &dir[0], "potato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Multi-block directory ---" echo "--- Multi-block directory ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "cactus") => 0; lfs1_mkdir(&lfs1, "cactus") => 0;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "cactus/test%d", i); sprintf((char*)buffer, "cactus/test%d", i);
lfs_mkdir(&lfs, (char*)buffer) => 0; lfs1_mkdir(&lfs1, (char*)buffer) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "cactus") => 0; lfs1_dir_open(&lfs1, &dir[0], "cactus") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "test%d", i); sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
} }
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Directory remove ---" echo "--- Directory remove ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; lfs1_remove(&lfs1, "potato") => LFS1_ERR_NOTEMPTY;
lfs_remove(&lfs, "potato/sweet") => 0; lfs1_remove(&lfs1, "potato/sweet") => 0;
lfs_remove(&lfs, "potato/baked") => 0; lfs1_remove(&lfs1, "potato/baked") => 0;
lfs_remove(&lfs, "potato/fried") => 0; lfs1_remove(&lfs1, "potato/fried") => 0;
lfs_dir_open(&lfs, &dir[0], "potato") => 0; lfs1_dir_open(&lfs1, &dir[0], "potato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_remove(&lfs, "potato") => 0; lfs1_remove(&lfs1, "potato") => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0; strcmp(info.name, "cactus") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0; strcmp(info.name, "cactus") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Directory rename ---" echo "--- Directory rename ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0; lfs1_mkdir(&lfs1, "coldpotato") => 0;
lfs_mkdir(&lfs, "coldpotato/baked") => 0; lfs1_mkdir(&lfs1, "coldpotato/baked") => 0;
lfs_mkdir(&lfs, "coldpotato/sweet") => 0; lfs1_mkdir(&lfs1, "coldpotato/sweet") => 0;
lfs_mkdir(&lfs, "coldpotato/fried") => 0; lfs1_mkdir(&lfs1, "coldpotato/fried") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; lfs1_rename(&lfs1, "coldpotato", "hotpotato") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "hotpotato") => 0; lfs1_dir_open(&lfs1, &dir[0], "hotpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "warmpotato") => 0; lfs1_mkdir(&lfs1, "warmpotato") => 0;
lfs_mkdir(&lfs, "warmpotato/mushy") => 0; lfs1_mkdir(&lfs1, "warmpotato/mushy") => 0;
lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERR_NOTEMPTY; lfs1_rename(&lfs1, "hotpotato", "warmpotato") => LFS1_ERR_NOTEMPTY;
lfs_remove(&lfs, "warmpotato/mushy") => 0; lfs1_remove(&lfs1, "warmpotato/mushy") => 0;
lfs_rename(&lfs, "hotpotato", "warmpotato") => 0; lfs1_rename(&lfs1, "hotpotato", "warmpotato") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "warmpotato") => 0; lfs1_dir_open(&lfs1, &dir[0], "warmpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0; lfs1_mkdir(&lfs1, "coldpotato") => 0;
lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; lfs1_rename(&lfs1, "warmpotato/baked", "coldpotato/baked") => 0;
lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; lfs1_rename(&lfs1, "warmpotato/sweet", "coldpotato/sweet") => 0;
lfs_rename(&lfs, "warmpotato/fried", "coldpotato/fried") => 0; lfs1_rename(&lfs1, "warmpotato/fried", "coldpotato/fried") => 0;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; lfs1_remove(&lfs1, "coldpotato") => LFS1_ERR_NOTEMPTY;
lfs_remove(&lfs, "warmpotato") => 0; lfs1_remove(&lfs1, "warmpotato") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0; lfs1_dir_open(&lfs1, &dir[0], "coldpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0; strcmp(info.name, "baked") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0; strcmp(info.name, "sweet") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0; strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Recursive remove ---" echo "--- Recursive remove ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; lfs1_remove(&lfs1, "coldpotato") => LFS1_ERR_NOTEMPTY;
lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0; lfs1_dir_open(&lfs1, &dir[0], "coldpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
while (true) { while (true) {
int err = lfs_dir_read(&lfs, &dir[0], &info); int err = lfs1_dir_read(&lfs1, &dir[0], &info);
err >= 0 => 1; err >= 0 => 1;
if (err == 0) { if (err == 0) {
break; break;
@@ -301,124 +301,183 @@ tests/test.py << TEST
strcpy((char*)buffer, "coldpotato/"); strcpy((char*)buffer, "coldpotato/");
strcat((char*)buffer, info.name); strcat((char*)buffer, info.name);
lfs_remove(&lfs, (char*)buffer) => 0; lfs1_remove(&lfs1, (char*)buffer) => 0;
} }
lfs_remove(&lfs, "coldpotato") => 0; lfs1_remove(&lfs1, "coldpotato") => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0; strcmp(info.name, "cactus") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST
echo "--- Multi-block rename ---"
tests/test.py << TEST
lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "cactus/test%d", i);
sprintf((char*)wbuffer, "cactus/tedd%d", i);
lfs1_rename(&lfs1, (char*)buffer, (char*)wbuffer) => 0;
}
lfs1_unmount(&lfs1) => 0;
TEST
tests/test.py << TEST
lfs1_mount(&lfs1, &cfg) => 0;
lfs1_dir_open(&lfs1, &dir[0], "cactus") => 0;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS1_TYPE_DIR;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS1_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "tedd%d", i);
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
info.type => LFS1_TYPE_DIR;
}
lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Multi-block remove ---" echo "--- Multi-block remove ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY; lfs1_remove(&lfs1, "cactus") => LFS1_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "cactus/test%d", i); sprintf((char*)buffer, "cactus/tedd%d", i);
lfs_remove(&lfs, (char*)buffer) => 0; lfs1_remove(&lfs1, (char*)buffer) => 0;
} }
lfs_remove(&lfs, "cactus") => 0; lfs1_remove(&lfs1, "cactus") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Multi-block directory with files ---" echo "--- Multi-block directory with files ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "prickly-pear") => 0; lfs1_mkdir(&lfs1, "prickly-pear") => 0;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "prickly-pear/test%d", i); sprintf((char*)buffer, "prickly-pear/test%d", i);
lfs_file_open(&lfs, &file[0], (char*)buffer, lfs1_file_open(&lfs1, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = 6; size = 6;
memcpy(wbuffer, "Hello", size); memcpy(wbuffer, "Hello", size);
lfs_file_write(&lfs, &file[0], wbuffer, size) => size; lfs1_file_write(&lfs1, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0; lfs1_dir_open(&lfs1, &dir[0], "prickly-pear") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "test%d", i); sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 6; info.size => 6;
} }
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST
echo "--- Multi-block rename with files ---"
tests/test.py << TEST
lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "prickly-pear/test%d", i);
sprintf((char*)wbuffer, "prickly-pear/tedd%d", i);
lfs1_rename(&lfs1, (char*)buffer, (char*)wbuffer) => 0;
}
lfs1_unmount(&lfs1) => 0;
TEST
tests/test.py << TEST
lfs1_mount(&lfs1, &cfg) => 0;
lfs1_dir_open(&lfs1, &dir[0], "prickly-pear") => 0;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS1_TYPE_DIR;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS1_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "tedd%d", i);
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
info.type => LFS1_TYPE_REG;
info.size => 6;
}
lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Multi-block remove with files ---" echo "--- Multi-block remove with files ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; lfs1_remove(&lfs1, "prickly-pear") => LFS1_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "prickly-pear/test%d", i); sprintf((char*)buffer, "prickly-pear/tedd%d", i);
lfs_remove(&lfs, (char*)buffer) => 0; lfs1_remove(&lfs1, (char*)buffer) => 0;
} }
lfs_remove(&lfs, "prickly-pear") => 0; lfs1_remove(&lfs1, "prickly-pear") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -1,221 +0,0 @@
#!/bin/bash
set -eu
# Note: These tests are intended for 512 byte inline size at different
# inline sizes they should still pass, but won't be testing anything
echo "=== Entry tests ==="
rm -rf blocks
function read_file {
cat << TEST
size = $2;
lfs_file_open(&lfs, &file[0], "$1", 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;
TEST
}
function write_file {
cat << TEST
size = $2;
lfs_file_open(&lfs, &file[0], "$1",
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;
TEST
}
echo "--- Entry grow test ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 20)
$(write_file "hi1" 20)
$(write_file "hi2" 20)
$(write_file "hi3" 20)
$(read_file "hi1" 20)
$(write_file "hi1" 200)
$(read_file "hi0" 20)
$(read_file "hi1" 200)
$(read_file "hi2" 20)
$(read_file "hi3" 20)
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry shrink test ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 20)
$(write_file "hi1" 200)
$(write_file "hi2" 20)
$(write_file "hi3" 20)
$(read_file "hi1" 200)
$(write_file "hi1" 20)
$(read_file "hi0" 20)
$(read_file "hi1" 20)
$(read_file "hi2" 20)
$(read_file "hi3" 20)
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry spill test ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 200)
$(write_file "hi2" 200)
$(write_file "hi3" 200)
$(read_file "hi0" 200)
$(read_file "hi1" 200)
$(read_file "hi2" 200)
$(read_file "hi3" 200)
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry push spill test ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 20)
$(write_file "hi2" 200)
$(write_file "hi3" 200)
$(read_file "hi1" 20)
$(write_file "hi1" 200)
$(read_file "hi0" 200)
$(read_file "hi1" 200)
$(read_file "hi2" 200)
$(read_file "hi3" 200)
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry push spill two test ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 20)
$(write_file "hi2" 200)
$(write_file "hi3" 200)
$(write_file "hi4" 200)
$(read_file "hi1" 20)
$(write_file "hi1" 200)
$(read_file "hi0" 200)
$(read_file "hi1" 200)
$(read_file "hi2" 200)
$(read_file "hi3" 200)
$(read_file "hi4" 200)
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry drop test ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 200)
$(write_file "hi2" 200)
$(write_file "hi3" 200)
lfs_remove(&lfs, "hi1") => 0;
lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT;
$(read_file "hi0" 200)
$(read_file "hi2" 200)
$(read_file "hi3" 200)
lfs_remove(&lfs, "hi2") => 0;
lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT;
$(read_file "hi0" 200)
$(read_file "hi3" 200)
lfs_remove(&lfs, "hi3") => 0;
lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT;
$(read_file "hi0" 200)
lfs_remove(&lfs, "hi0") => 0;
lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Create too big ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 'm', 200);
buffer[200] = '\0';
size = 400;
lfs_file_open(&lfs, &file[0], (char*)buffer,
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;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Resize too big ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 'm', 200);
buffer[200] = '\0';
size = 40;
lfs_file_open(&lfs, &file[0], (char*)buffer,
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 = 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;
lfs_file_open(&lfs, &file[0], (char*)buffer,
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;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"
tests/stats.py

View File

@@ -8,65 +8,65 @@ LARGESIZE=262144
echo "=== File tests ===" echo "=== File tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
echo "--- Simple file test ---" echo "--- Simple file test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[0], "hello", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = strlen("Hello World!\n"); size = strlen("Hello World!\n");
memcpy(wbuffer, "Hello World!\n", size); memcpy(wbuffer, "Hello World!\n", size);
lfs_file_write(&lfs, &file[0], wbuffer, size) => size; lfs1_file_write(&lfs1, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "hello", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "hello", LFS1_O_RDONLY) => 0;
size = strlen("Hello World!\n"); size = strlen("Hello World!\n");
lfs_file_read(&lfs, &file[0], rbuffer, size) => size; lfs1_file_read(&lfs1, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0; memcmp(rbuffer, wbuffer, size) => 0;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
w_test() { w_test() {
tests/test.py << TEST tests/test.py << TEST
size = $1; size = $1;
lfs_size_t chunk = 31; lfs1_size_t chunk = 31;
srand(0); srand(0);
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "$2", lfs1_file_open(&lfs1, &file[0], "$2",
${3:-LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC}) => 0; ${3:-LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_TRUNC}) => 0;
for (lfs_size_t i = 0; i < size; i += chunk) { for (lfs1_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 (lfs1_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff; buffer[b] = rand() & 0xff;
} }
lfs_file_write(&lfs, &file[0], buffer, chunk) => chunk; lfs1_file_write(&lfs1, &file[0], buffer, chunk) => chunk;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
r_test() { r_test() {
tests/test.py << TEST tests/test.py << TEST
size = $1; size = $1;
lfs_size_t chunk = 29; lfs1_size_t chunk = 29;
srand(0); srand(0);
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "$2", &info) => 0; lfs1_stat(&lfs1, "$2", &info) => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => size; info.size => size;
lfs_file_open(&lfs, &file[0], "$2", ${3:-LFS_O_RDONLY}) => 0; lfs1_file_open(&lfs1, &file[0], "$2", ${3:-LFS1_O_RDONLY}) => 0;
for (lfs_size_t i = 0; i < size; i += chunk) { for (lfs1_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[0], buffer, chunk) => chunk; lfs1_file_read(&lfs1, &file[0], buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk && i+b < size; b++) { for (lfs1_size_t b = 0; b < chunk && i+b < size; b++) {
buffer[b] => rand() & 0xff; buffer[b] => rand() & 0xff;
} }
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }
@@ -106,52 +106,52 @@ r_test 0 noavacado
echo "--- Dir check ---" echo "--- Dir check ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => strlen("Hello World!\n"); info.size => strlen("Hello World!\n");
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "smallavacado") => 0; strcmp(info.name, "smallavacado") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => $SMALLSIZE; info.size => $SMALLSIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "mediumavacado") => 0; strcmp(info.name, "mediumavacado") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => $MEDIUMSIZE; info.size => $MEDIUMSIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "largeavacado") => 0; strcmp(info.name, "largeavacado") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => $LARGESIZE; info.size => $LARGESIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "noavacado") => 0; strcmp(info.name, "noavacado") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 0; info.size => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Many file test ---" echo "--- Many file test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
// Create 300 files of 6 bytes // Create 300 files of 6 bytes
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "directory") => 0; lfs1_mkdir(&lfs1, "directory") => 0;
for (unsigned i = 0; i < 300; i++) { for (unsigned i = 0; i < 300; i++) {
snprintf((char*)buffer, sizeof(buffer), "file_%03d", i); snprintf((char*)buffer, sizeof(buffer), "file_%03d", i);
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[0], (char*)buffer, LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
size = 6; size = 6;
memcpy(wbuffer, "Hello", size); memcpy(wbuffer, "Hello", size);
lfs_file_write(&lfs, &file[0], wbuffer, size) => size; lfs1_file_write(&lfs1, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -6,45 +6,43 @@ rm -rf blocks
echo "--- Basic formatting ---" echo "--- Basic formatting ---"
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST
echo "--- Basic mounting ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_unmount(&lfs) => 0;
TEST 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
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; lfs1_format(&lfs1, &cfg) => LFS1_ERR_CORRUPT;
TEST TEST
rm blocks/0 blocks/1 rm blocks/0 blocks/1
echo "--- Invalid mount ---" echo "--- Basic mounting ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs1_format(&lfs1, &cfg) => 0;
TEST
tests/test.py << TEST
lfs1_mount(&lfs1, &cfg) => 0;
lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Expanding superblock ---" echo "--- Invalid mount ---"
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (int i = 0; i < 100; i++) {
lfs_mkdir(&lfs, "dummy") => 0;
lfs_remove(&lfs, "dummy") => 0;
}
lfs_unmount(&lfs) => 0;
TEST TEST
rm blocks/0 blocks/1
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => LFS1_ERR_CORRUPT;
lfs_mkdir(&lfs, "dummy") => 0; TEST
lfs_unmount(&lfs) => 0;
echo "--- Valid corrupt mount ---"
tests/test.py << TEST
lfs1_format(&lfs1, &cfg) => 0;
TEST
rm blocks/0
tests/test.py << TEST
lfs1_mount(&lfs1, &cfg) => 0;
lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -4,182 +4,182 @@ set -eu
echo "=== Interspersed tests ===" echo "=== Interspersed tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
echo "--- Interspersed file test ---" echo "--- Interspersed file test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[0], "a", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
lfs_file_open(&lfs, &file[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[1], "b", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
lfs_file_open(&lfs, &file[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[2], "c", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
lfs_file_open(&lfs, &file[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[3], "d", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_write(&lfs, &file[0], (const void*)"a", 1) => 1; lfs1_file_write(&lfs1, &file[0], (const void*)"a", 1) => 1;
lfs_file_write(&lfs, &file[1], (const void*)"b", 1) => 1; lfs1_file_write(&lfs1, &file[1], (const void*)"b", 1) => 1;
lfs_file_write(&lfs, &file[2], (const void*)"c", 1) => 1; lfs1_file_write(&lfs1, &file[2], (const void*)"c", 1) => 1;
lfs_file_write(&lfs, &file[3], (const void*)"d", 1) => 1; lfs1_file_write(&lfs1, &file[3], (const void*)"d", 1) => 1;
} }
lfs_file_close(&lfs, &file[0]); lfs1_file_close(&lfs1, &file[0]);
lfs_file_close(&lfs, &file[1]); lfs1_file_close(&lfs1, &file[1]);
lfs_file_close(&lfs, &file[2]); lfs1_file_close(&lfs1, &file[2]);
lfs_file_close(&lfs, &file[3]); lfs1_file_close(&lfs1, &file[3]);
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "a") => 0; strcmp(info.name, "a") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "b") => 0; strcmp(info.name, "b") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "c") => 0; strcmp(info.name, "c") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "d") => 0; strcmp(info.name, "d") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_file_open(&lfs, &file[0], "a", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "a", LFS1_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[1], "b", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[1], "b", LFS1_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[2], "c", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[2], "c", LFS1_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[3], "d", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[3], "d", LFS1_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_read(&lfs, &file[0], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[0], buffer, 1) => 1;
buffer[0] => 'a'; buffer[0] => 'a';
lfs_file_read(&lfs, &file[1], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[1], buffer, 1) => 1;
buffer[0] => 'b'; buffer[0] => 'b';
lfs_file_read(&lfs, &file[2], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[2], buffer, 1) => 1;
buffer[0] => 'c'; buffer[0] => 'c';
lfs_file_read(&lfs, &file[3], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[3], buffer, 1) => 1;
buffer[0] => 'd'; buffer[0] => 'd';
} }
lfs_file_close(&lfs, &file[0]); lfs1_file_close(&lfs1, &file[0]);
lfs_file_close(&lfs, &file[1]); lfs1_file_close(&lfs1, &file[1]);
lfs_file_close(&lfs, &file[2]); lfs1_file_close(&lfs1, &file[2]);
lfs_file_close(&lfs, &file[3]); lfs1_file_close(&lfs1, &file[3]);
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Interspersed remove file test ---" echo "--- Interspersed remove file test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1;
} }
lfs_remove(&lfs, "a") => 0; lfs1_remove(&lfs1, "a") => 0;
lfs_remove(&lfs, "b") => 0; lfs1_remove(&lfs1, "b") => 0;
lfs_remove(&lfs, "c") => 0; lfs1_remove(&lfs1, "c") => 0;
lfs_remove(&lfs, "d") => 0; lfs1_remove(&lfs1, "d") => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1;
} }
lfs_file_close(&lfs, &file[0]); lfs1_file_close(&lfs1, &file[0]);
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "e") => 0; strcmp(info.name, "e") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_read(&lfs, &file[0], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[0], buffer, 1) => 1;
buffer[0] => 'e'; buffer[0] => 'e';
} }
lfs_file_close(&lfs, &file[0]); lfs1_file_close(&lfs1, &file[0]);
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Remove inconveniently test ---" echo "--- Remove inconveniently test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0; lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_WRONLY | LFS1_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[1], "f", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
lfs_file_open(&lfs, &file[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs1_file_open(&lfs1, &file[2], "g", LFS1_O_WRONLY | LFS1_O_CREAT) => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1; lfs1_file_write(&lfs1, &file[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1; lfs1_file_write(&lfs1, &file[2], (const void*)"g", 1) => 1;
} }
lfs_remove(&lfs, "f") => 0; lfs1_remove(&lfs1, "f") => 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1; lfs1_file_write(&lfs1, &file[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1; lfs1_file_write(&lfs1, &file[2], (const void*)"g", 1) => 1;
} }
lfs_file_close(&lfs, &file[0]); lfs1_file_close(&lfs1, &file[0]);
lfs_file_close(&lfs, &file[1]); lfs1_file_close(&lfs1, &file[1]);
lfs_file_close(&lfs, &file[2]); lfs1_file_close(&lfs1, &file[2]);
lfs_dir_open(&lfs, &dir[0], "/") => 0; lfs1_dir_open(&lfs1, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "e") => 0; strcmp(info.name, "e") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "g") => 0; strcmp(info.name, "g") => 0;
info.type => LFS_TYPE_REG; info.type => LFS1_TYPE_REG;
info.size => 10; info.size => 10;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[1], "g", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[1], "g", LFS1_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
lfs_file_read(&lfs, &file[0], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[0], buffer, 1) => 1;
buffer[0] => 'e'; buffer[0] => 'e';
lfs_file_read(&lfs, &file[1], buffer, 1) => 1; lfs1_file_read(&lfs1, &file[1], buffer, 1) => 1;
buffer[0] => 'g'; buffer[0] => 'g';
} }
lfs_file_close(&lfs, &file[0]); lfs1_file_close(&lfs1, &file[0]);
lfs_file_close(&lfs, &file[1]); lfs1_file_close(&lfs1, &file[1]);
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -4,327 +4,231 @@ set -eu
echo "=== Move tests ===" echo "=== Move tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs1_mkdir(&lfs1, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs1_mkdir(&lfs1, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs1_mkdir(&lfs1, "c") => 0;
lfs_mkdir(&lfs, "d") => 0; lfs1_mkdir(&lfs1, "d") => 0;
lfs_mkdir(&lfs, "a/hi") => 0; lfs1_mkdir(&lfs1, "a/hi") => 0;
lfs_mkdir(&lfs, "a/hi/hola") => 0; lfs1_mkdir(&lfs1, "a/hi/hola") => 0;
lfs_mkdir(&lfs, "a/hi/bonjour") => 0; lfs1_mkdir(&lfs1, "a/hi/bonjour") => 0;
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs1_mkdir(&lfs1, "a/hi/ohayo") => 0;
lfs_file_open(&lfs, &file[0], "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs1_file_open(&lfs1, &file[0], "a/hello", LFS1_O_CREAT | LFS1_O_WRONLY) => 0;
lfs_file_write(&lfs, &file[0], "hola\n", 5) => 5; lfs1_file_write(&lfs1, &file[0], "hola\n", 5) => 5;
lfs_file_write(&lfs, &file[0], "bonjour\n", 8) => 8; lfs1_file_write(&lfs1, &file[0], "bonjour\n", 8) => 8;
lfs_file_write(&lfs, &file[0], "ohayo\n", 6) => 6; lfs1_file_write(&lfs1, &file[0], "ohayo\n", 6) => 6;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Move file ---" echo "--- Move file ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs1_rename(&lfs1, "a/hello", "b/hello") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "a") => 0; lfs1_dir_open(&lfs1, &dir[0], "a") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0; lfs1_dir_open(&lfs1, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Move file corrupt source ---" echo "--- Move file corrupt source ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs1_rename(&lfs1, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/corrupt.py -n 1 rm -v blocks/7
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0; lfs1_dir_open(&lfs1, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0; lfs1_dir_open(&lfs1, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Move file corrupt source and dest ---" echo "--- Move file corrupt source and dest ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs1_rename(&lfs1, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/corrupt.py -n 2 rm -v blocks/8
rm -v blocks/a
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0; lfs1_dir_open(&lfs1, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "d") => 0; lfs1_dir_open(&lfs1, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST
echo "--- Move file after corrupt ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Move dir ---" echo "--- Move dir ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "b/hi") => 0; lfs1_rename(&lfs1, "a/hi", "b/hi") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "a") => 0; lfs1_dir_open(&lfs1, &dir[0], "a") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0; lfs1_dir_open(&lfs1, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Move dir corrupt source ---" echo "--- Move dir corrupt source ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "b/hi", "c/hi") => 0; lfs1_rename(&lfs1, "b/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/corrupt.py -n 1 rm -v blocks/7
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0; lfs1_dir_open(&lfs1, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0; lfs1_dir_open(&lfs1, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Move dir corrupt source and dest ---" echo "--- Move dir corrupt source and dest ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_rename(&lfs, "c/hi", "d/hi") => 0; lfs1_rename(&lfs1, "c/hi", "d/hi") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/corrupt.py -n 2 rm -v blocks/9
rm -v blocks/a
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0; lfs1_dir_open(&lfs1, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0; strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move dir after corrupt ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hi", "d/hi") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "d") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0; strcmp(info.name, "hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs1_dir_open(&lfs1, &dir[0], "d") => 0;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Move check ---" echo "--- Move check ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "a/hi") => LFS1_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "b/hi") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "b/hi") => LFS1_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "c/hi") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "d/hi") => LFS1_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "d/hi") => 0; lfs1_dir_open(&lfs1, &dir[0], "c/hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "hola") => 0; strcmp(info.name, "hola") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0; strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "ohayo") => 0; strcmp(info.name, "ohayo") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0; lfs1_dir_read(&lfs1, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "a/hello") => LFS1_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "b/hello") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "b/hello") => LFS1_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "c/hello") => LFS_ERR_NOENT; lfs1_dir_open(&lfs1, &dir[0], "d/hello") => LFS1_ERR_NOENT;
lfs_file_open(&lfs, &file[0], "d/hello", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "c/hello", LFS1_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], buffer, 5) => 5; lfs1_file_read(&lfs1, &file[0], buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0; memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file[0], buffer, 8) => 8; lfs1_file_read(&lfs1, &file[0], buffer, 8) => 8;
memcmp(buffer, "bonjour\n", 8) => 0; memcmp(buffer, "bonjour\n", 8) => 0;
lfs_file_read(&lfs, &file[0], buffer, 6) => 6; lfs1_file_read(&lfs1, &file[0], buffer, 6) => 6;
memcmp(buffer, "ohayo\n", 6) => 0; memcmp(buffer, "ohayo\n", 6) => 0;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST
echo "--- Move state stealing ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "b") => 0;
lfs_remove(&lfs, "c") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "b") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "c") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "d/hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hola") => 0;
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;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "b") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "c") => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file[0], "d/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file[0], buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file[0], buffer, 8) => 8;
memcmp(buffer, "bonjour\n", 8) => 0;
lfs_file_read(&lfs, &file[0], buffer, 6) => 6;
memcmp(buffer, "ohayo\n", 6) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST TEST

View File

@@ -4,41 +4,37 @@ set -eu
echo "=== Orphan tests ===" echo "=== Orphan tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
echo "--- Orphan test ---" echo "--- Orphan test ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0; lfs1_mkdir(&lfs1, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0; lfs1_mkdir(&lfs1, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0; lfs1_mkdir(&lfs1, "parent/child") => 0;
lfs_remove(&lfs, "parent/orphan") => 0; lfs1_remove(&lfs1, "parent/orphan") => 0;
TEST TEST
# corrupt most recent commit, this should be the update to the previous # remove most recent file, this should be the update to the previous
# linked-list entry and should orphan the child # linked-list entry and should orphan the child
tests/corrupt.py rm -v blocks/8
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs1_stat(&lfs1, "parent/orphan", &info) => LFS1_ERR_NOENT;
unsigned before = 0;
lfs1_traverse(&lfs1, test_count, &before) => 0;
test_log("before", before);
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs1_deorphan(&lfs1) => 0;
lfs_ssize_t before = lfs_fs_size(&lfs);
before => 8;
lfs_unmount(&lfs) => 0; lfs1_stat(&lfs1, "parent/orphan", &info) => LFS1_ERR_NOENT;
lfs_mount(&lfs, &cfg) => 0; unsigned after = 0;
lfs1_traverse(&lfs1, test_count, &after) => 0;
test_log("after", after);
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; int diff = before - after;
lfs_ssize_t orphaned = lfs_fs_size(&lfs); diff => 2;
orphaned => 8; lfs1_unmount(&lfs1) => 0;
lfs_mkdir(&lfs, "parent/otherchild") => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_ssize_t deorphaned = lfs_fs_size(&lfs);
deorphaned => 8;
lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -4,157 +4,139 @@ set -eu
echo "=== Path tests ===" echo "=== Path tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs1_mkdir(&lfs1, "tea") => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs1_mkdir(&lfs1, "coffee") => 0;
lfs_mkdir(&lfs, "soda") => 0; lfs1_mkdir(&lfs1, "soda") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs1_mkdir(&lfs1, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs1_mkdir(&lfs1, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs1_mkdir(&lfs1, "tea/coldtea") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs1_mkdir(&lfs1, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs1_mkdir(&lfs1, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs1_mkdir(&lfs1, "coffee/coldcoffee") => 0;
lfs_mkdir(&lfs, "soda/hotsoda") => 0; lfs1_mkdir(&lfs1, "soda/hotsoda") => 0;
lfs_mkdir(&lfs, "soda/warmsoda") => 0; lfs1_mkdir(&lfs1, "soda/warmsoda") => 0;
lfs_mkdir(&lfs, "soda/coldsoda") => 0; lfs1_mkdir(&lfs1, "soda/coldsoda") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Root path tests ---" echo "--- Root path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "tea/hottea", &info) => 0; lfs1_stat(&lfs1, "tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs1_stat(&lfs1, "/tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_mkdir(&lfs, "/milk1") => 0; lfs1_mkdir(&lfs1, "/milk1") => 0;
lfs_stat(&lfs, "/milk1", &info) => 0; lfs1_stat(&lfs1, "/milk1", &info) => 0;
strcmp(info.name, "milk1") => 0; strcmp(info.name, "milk1") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Redundant slash path tests ---" echo "--- Redundant slash path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs1_stat(&lfs1, "/tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "//tea//hottea", &info) => 0; lfs1_stat(&lfs1, "//tea//hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "///tea///hottea", &info) => 0; lfs1_stat(&lfs1, "///tea///hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_mkdir(&lfs, "///milk2") => 0; lfs1_mkdir(&lfs1, "///milk2") => 0;
lfs_stat(&lfs, "///milk2", &info) => 0; lfs1_stat(&lfs1, "///milk2", &info) => 0;
strcmp(info.name, "milk2") => 0; strcmp(info.name, "milk2") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Dot path tests ---" echo "--- Dot path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "./tea/hottea", &info) => 0; lfs1_stat(&lfs1, "./tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "/./tea/hottea", &info) => 0; lfs1_stat(&lfs1, "/./tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "/././tea/hottea", &info) => 0; lfs1_stat(&lfs1, "/././tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; lfs1_stat(&lfs1, "/./tea/./hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_mkdir(&lfs, "/./milk3") => 0; lfs1_mkdir(&lfs1, "/./milk3") => 0;
lfs_stat(&lfs, "/./milk3", &info) => 0; lfs1_stat(&lfs1, "/./milk3", &info) => 0;
strcmp(info.name, "milk3") => 0; strcmp(info.name, "milk3") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Dot dot path tests ---" echo "--- Dot dot path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; lfs1_stat(&lfs1, "coffee/../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; lfs1_stat(&lfs1, "tea/coldtea/../hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; lfs1_stat(&lfs1, "coffee/coldcoffee/../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "coffee/../soda/../tea/hottea", &info) => 0; lfs1_stat(&lfs1, "coffee/../soda/../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_mkdir(&lfs, "coffee/../milk4") => 0; lfs1_mkdir(&lfs1, "coffee/../milk4") => 0;
lfs_stat(&lfs, "coffee/../milk4", &info) => 0; lfs1_stat(&lfs1, "coffee/../milk4", &info) => 0;
strcmp(info.name, "milk4") => 0; strcmp(info.name, "milk4") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Trailing dot path tests ---" echo "--- Trailing dot path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "tea/hottea/", &info) => 0; lfs1_stat(&lfs1, "tea/hottea/", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "tea/hottea/.", &info) => 0; lfs1_stat(&lfs1, "tea/hottea/.", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; lfs1_stat(&lfs1, "tea/hottea/./.", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_stat(&lfs, "tea/hottea/..", &info) => 0; lfs1_stat(&lfs1, "tea/hottea/..", &info) => 0;
strcmp(info.name, "tea") => 0; strcmp(info.name, "tea") => 0;
lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; lfs1_stat(&lfs1, "tea/hottea/../.", &info) => 0;
strcmp(info.name, "tea") => 0; strcmp(info.name, "tea") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Root dot dot path tests ---" echo "--- Root dot dot path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; lfs1_stat(&lfs1, "coffee/../../../../../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
lfs_mkdir(&lfs, "coffee/../../../../../../milk5") => 0; lfs1_mkdir(&lfs1, "coffee/../../../../../../milk5") => 0;
lfs_stat(&lfs, "coffee/../../../../../../milk5", &info) => 0; lfs1_stat(&lfs1, "coffee/../../../../../../milk5", &info) => 0;
strcmp(info.name, "milk5") => 0; strcmp(info.name, "milk5") => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Root tests ---" echo "--- Root tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0; lfs1_stat(&lfs1, "/", &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS1_TYPE_DIR;
strcmp(info.name, "/") => 0; strcmp(info.name, "/") => 0;
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs1_mkdir(&lfs1, "/") => LFS1_ERR_EXIST;
lfs_file_open(&lfs, &file[0], "/", LFS_O_WRONLY | LFS_O_CREAT) lfs1_file_open(&lfs1, &file[0], "/", LFS1_O_WRONLY | LFS1_O_CREAT)
=> LFS_ERR_ISDIR; => LFS1_ERR_ISDIR;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Sketchy path tests ---" echo "--- Sketchy path tests ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; lfs1_mkdir(&lfs1, "dirt/ground") => LFS1_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs1_mkdir(&lfs1, "dirt/ground/earth") => LFS1_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST
echo "--- Max path test ---"
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 'w', LFS_NAME_MAX+1);
buffer[LFS_NAME_MAX+2] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => LFS_ERR_NAMETOOLONG;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG;
memcpy(buffer, "coffee/", strlen("coffee/"));
memset(buffer+strlen("coffee/"), 'w', LFS_NAME_MAX+1);
buffer[strlen("coffee/")+LFS_NAME_MAX+2] = '\0';
lfs_mkdir(&lfs, (char*)buffer) => LFS_ERR_NAMETOOLONG;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG;
lfs_unmount(&lfs) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -8,353 +8,353 @@ LARGESIZE=132
echo "=== Seek tests ===" echo "=== Seek tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs1_mkdir(&lfs1, "hello") => 0;
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "hello/kitty%d", i); sprintf((char*)buffer, "hello/kitty%d", i);
lfs_file_open(&lfs, &file[0], (char*)buffer, lfs1_file_open(&lfs1, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_APPEND) => 0;
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[0], buffer, size); lfs1_file_write(&lfs1, &file[0], buffer, size);
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Simple dir seek ---" echo "--- Simple dir seek ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "hello") => 0; lfs1_dir_open(&lfs1, &dir[0], "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_soff_t pos; lfs1_soff_t pos;
int i; int i;
for (i = 0; i < $SMALLSIZE; i++) { for (i = 0; i < $SMALLSIZE; i++) {
sprintf((char*)buffer, "kitty%d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
pos = lfs_dir_tell(&lfs, &dir[0]); pos = lfs1_dir_tell(&lfs1, &dir[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_dir_seek(&lfs, &dir[0], pos) => 0; lfs1_dir_seek(&lfs1, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_rewind(&lfs, &dir[0]) => 0; lfs1_dir_rewind(&lfs1, &dir[0]) => 0;
sprintf((char*)buffer, "kitty%d", 0); sprintf((char*)buffer, "kitty%d", 0);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_seek(&lfs, &dir[0], pos) => 0; lfs1_dir_seek(&lfs1, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Large dir seek ---" echo "--- Large dir seek ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "hello") => 0; lfs1_dir_open(&lfs1, &dir[0], "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_soff_t pos; lfs1_soff_t pos;
int i; int i;
for (i = 0; i < $MEDIUMSIZE; i++) { for (i = 0; i < $MEDIUMSIZE; i++) {
sprintf((char*)buffer, "kitty%d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
pos = lfs_dir_tell(&lfs, &dir[0]); pos = lfs1_dir_tell(&lfs1, &dir[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_dir_seek(&lfs, &dir[0], pos) => 0; lfs1_dir_seek(&lfs1, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_rewind(&lfs, &dir[0]) => 0; lfs1_dir_rewind(&lfs1, &dir[0]) => 0;
sprintf((char*)buffer, "kitty%d", 0); sprintf((char*)buffer, "kitty%d", 0);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0; strcmp(info.name, ".") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_seek(&lfs, &dir[0], pos) => 0; lfs1_dir_seek(&lfs1, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i); sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs1_dir_read(&lfs1, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0; lfs1_dir_close(&lfs1, &dir[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Simple file seek ---" echo "--- Simple file seek ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDONLY) => 0;
lfs_soff_t pos; lfs1_soff_t pos;
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[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file[0]); pos = lfs1_file_tell(&lfs1, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_rewind(&lfs, &file[0]) => 0; lfs1_file_rewind(&lfs1, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size; lfs1_file_seek(&lfs1, &file[0], size, LFS1_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos; lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file[0]); size = lfs1_file_size(&lfs1, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Large file seek ---" echo "--- Large file seek ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDONLY) => 0;
lfs_soff_t pos; lfs1_soff_t pos;
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[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file[0]); pos = lfs1_file_tell(&lfs1, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_rewind(&lfs, &file[0]) => 0; lfs1_file_rewind(&lfs1, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size; lfs1_file_seek(&lfs1, &file[0], size, LFS1_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos; lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file[0]); size = lfs1_file_size(&lfs1, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Simple file seek and write ---" echo "--- Simple file seek and write ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0;
lfs_soff_t pos; lfs1_soff_t pos;
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[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs_file_tell(&lfs, &file[0]); pos = lfs1_file_tell(&lfs1, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
memcpy(buffer, "doggodogdog", size); memcpy(buffer, "doggodogdog", size);
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_rewind(&lfs, &file[0]) => 0; lfs1_file_rewind(&lfs1, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file[0]); size = lfs1_file_size(&lfs1, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Large file seek and write ---" echo "--- Large file seek and write ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0;
lfs_soff_t pos; lfs1_soff_t pos;
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[0], buffer, size) => size; lfs1_file_read(&lfs1, &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[0]); pos = lfs1_file_tell(&lfs1, &file[0]);
} }
pos >= 0 => 1; pos >= 0 => 1;
memcpy(buffer, "doggodogdog", size); memcpy(buffer, "doggodogdog", size);
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_rewind(&lfs, &file[0]) => 0; lfs1_file_rewind(&lfs1, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0; memcmp(buffer, "doggodogdog", size) => 0;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
size = lfs_file_size(&lfs, &file[0]); size = lfs1_file_size(&lfs1, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Boundary seek and write ---" echo "--- Boundary seek and write ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0;
size = strlen("hedgehoghog"); size = strlen("hedgehoghog");
const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; const lfs1_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs_soff_t off = offsets[i]; lfs1_soff_t off = offsets[i];
memcpy(buffer, "hedgehoghog", size); memcpy(buffer, "hedgehoghog", size);
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; lfs1_file_seek(&lfs1, &file[0], off, LFS1_SEEK_SET) => off;
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; lfs1_file_seek(&lfs1, &file[0], off, LFS1_SEEK_SET) => off;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0; memcmp(buffer, "hedgehoghog", size) => 0;
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_SET) => 0; lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_SET) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0; memcmp(buffer, "kittycatcat", size) => 0;
lfs_file_sync(&lfs, &file[0]) => 0; lfs1_file_sync(&lfs1, &file[0]) => 0;
} }
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Out-of-bounds seek ---" echo "--- Out-of-bounds seek ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
lfs_file_size(&lfs, &file[0]) => $LARGESIZE*size; lfs1_file_size(&lfs1, &file[0]) => $LARGESIZE*size;
lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size, lfs1_file_seek(&lfs1, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; LFS1_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs_file_read(&lfs, &file[0], buffer, size) => 0; lfs1_file_read(&lfs1, &file[0], buffer, size) => 0;
memcpy(buffer, "porcupineee", size); memcpy(buffer, "porcupineee", size);
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size, lfs1_file_seek(&lfs1, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; LFS1_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &file[0], buffer, size) => size;
memcmp(buffer, "porcupineee", size) => 0; memcmp(buffer, "porcupineee", size) => 0;
lfs_file_seek(&lfs, &file[0], $LARGESIZE*size, lfs1_file_seek(&lfs1, &file[0], $LARGESIZE*size,
LFS_SEEK_SET) => $LARGESIZE*size; LFS1_SEEK_SET) => $LARGESIZE*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &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[0], -(($LARGESIZE+$SMALLSIZE)*size), lfs1_file_seek(&lfs1, &file[0], -(($LARGESIZE+$SMALLSIZE)*size),
LFS_SEEK_CUR) => LFS_ERR_INVAL; LFS1_SEEK_CUR) => LFS1_ERR_INVAL;
lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size; lfs1_file_tell(&lfs1, &file[0]) => ($LARGESIZE+1)*size;
lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size), lfs1_file_seek(&lfs1, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size),
LFS_SEEK_END) => LFS_ERR_INVAL; LFS1_SEEK_END) => LFS1_ERR_INVAL;
lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size; lfs1_file_tell(&lfs1, &file[0]) => ($LARGESIZE+1)*size;
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
echo "--- Results ---" echo "--- Results ---"

View File

@@ -8,7 +8,7 @@ LARGESIZE=8192
echo "=== Truncate tests ===" echo "=== Truncate tests ==="
rm -rf blocks rm -rf blocks
tests/test.py << TEST tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0; lfs1_format(&lfs1, &cfg) => 0;
TEST TEST
truncate_test() { truncate_test() {
@@ -17,98 +17,98 @@ STARTSEEKS="$2"
HOTSIZES="$3" HOTSIZES="$3"
COLDSIZES="$4" COLDSIZES="$4"
tests/test.py << TEST tests/test.py << TEST
static const lfs_off_t startsizes[] = {$STARTSIZES}; static const lfs1_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t startseeks[] = {$STARTSEEKS}; static const lfs1_off_t startseeks[] = {$STARTSEEKS};
static const lfs_off_t hotsizes[] = {$HOTSIZES}; static const lfs1_off_t hotsizes[] = {$HOTSIZES};
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i); sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file[0], (const char*)buffer, lfs1_file_open(&lfs1, &file[0], (const char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_TRUNC) => 0;
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size = strlen((char*)buffer);
for (int j = 0; j < startsizes[i]; j += size) { for (lfs1_off_t j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size; lfs1_file_write(&lfs1, &file[0], buffer, size) => size;
} }
lfs_file_size(&lfs, &file[0]) => startsizes[i]; lfs1_file_size(&lfs1, &file[0]) => startsizes[i];
if (startseeks[i] != startsizes[i]) { if (startseeks[i] != startsizes[i]) {
lfs_file_seek(&lfs, &file[0], lfs1_file_seek(&lfs1, &file[0],
startseeks[i], LFS_SEEK_SET) => startseeks[i]; startseeks[i], LFS1_SEEK_SET) => startseeks[i];
} }
lfs_file_truncate(&lfs, &file[0], hotsizes[i]) => 0; lfs1_file_truncate(&lfs1, &file[0], hotsizes[i]) => 0;
lfs_file_size(&lfs, &file[0]) => hotsizes[i]; lfs1_file_size(&lfs1, &file[0]) => hotsizes[i];
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
static const lfs_off_t startsizes[] = {$STARTSIZES}; static const lfs1_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t hotsizes[] = {$HOTSIZES}; static const lfs1_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t coldsizes[] = {$COLDSIZES}; static const lfs1_off_t coldsizes[] = {$COLDSIZES};
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i); sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0; lfs1_file_open(&lfs1, &file[0], (const char*)buffer, LFS1_O_RDWR) => 0;
lfs_file_size(&lfs, &file[0]) => hotsizes[i]; lfs1_file_size(&lfs1, &file[0]) => hotsizes[i];
size = strlen("hair"); size = strlen("hair");
int j = 0; lfs1_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) { for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &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[0], buffer, size) => size; lfs1_file_read(&lfs1, &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[0], coldsizes[i]) => 0; lfs1_file_truncate(&lfs1, &file[0], coldsizes[i]) => 0;
lfs_file_size(&lfs, &file[0]) => coldsizes[i]; lfs1_file_size(&lfs1, &file[0]) => coldsizes[i];
lfs_file_close(&lfs, &file[0]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
tests/test.py << TEST tests/test.py << TEST
static const lfs_off_t startsizes[] = {$STARTSIZES}; static const lfs1_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t hotsizes[] = {$HOTSIZES}; static const lfs1_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t coldsizes[] = {$COLDSIZES}; static const lfs1_off_t coldsizes[] = {$COLDSIZES};
lfs_mount(&lfs, &cfg) => 0; lfs1_mount(&lfs1, &cfg) => 0;
for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i); sprintf((char*)buffer, "hairyhead%d", i);
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0; lfs1_file_open(&lfs1, &file[0], (const char*)buffer, LFS1_O_RDONLY) => 0;
lfs_file_size(&lfs, &file[0]) => coldsizes[i]; lfs1_file_size(&lfs1, &file[0]) => coldsizes[i];
size = strlen("hair"); size = strlen("hair");
int j = 0; lfs1_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) { j += size) {
lfs_file_read(&lfs, &file[0], buffer, size) => size; lfs1_file_read(&lfs1, &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[0], buffer, size) => size; lfs1_file_read(&lfs1, &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]) => 0; lfs1_file_close(&lfs1, &file[0]) => 0;
} }
lfs_unmount(&lfs) => 0; lfs1_unmount(&lfs1) => 0;
TEST TEST
} }