Compare commits

..

103 Commits

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

2
.gitignore vendored
View File

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

View File

@@ -18,17 +18,17 @@ script:
- make test QUIET=1
# run tests with a few different configurations
- make test QUIET=1 CFLAGS+="-DLFS2_READ_SIZE=1 -DLFS2_CACHE_SIZE=4"
- make test QUIET=1 CFLAGS+="-DLFS2_READ_SIZE=512 -DLFS2_CACHE_SIZE=512 -DLFS2_BLOCK_CYCLES=16"
- make test QUIET=1 CFLAGS+="-DLFS2_BLOCK_COUNT=1023 -DLFS2_LOOKAHEAD_SIZE=256"
- make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=4"
- make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_CACHE_SIZE=512 -DLFS_BLOCK_CYCLES=16"
- make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048"
- make clean test QUIET=1 CFLAGS+="-DLFS2_INLINE_MAX=0"
- make clean test QUIET=1 CFLAGS+="-DLFS2_NO_INTRINSICS"
- make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0"
- make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS"
# compile and find the code size with the smallest configuration
- make clean size
OBJ="$(ls lfs2*.o | tr '\n' ' ')"
CFLAGS+="-DLFS2_NO_ASSERT -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR"
OBJ="$(ls lfs*.o | tr '\n' ' ')"
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
| tee sizes
# update status if we succeeded, compare with master if possible
@@ -96,28 +96,58 @@ jobs:
- mips-linux-gnu-gcc --version
- qemu-mips -version
# self-host with littlefs-fuse for fuzz test
- stage: test
env:
- STAGE=test
- NAME=littlefs-fuse
install:
- sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2-alpha
- fusermount -V
- gcc --version
before_script:
# setup disk for littlefs-fuse
- rm -rf littlefs-fuse/littlefs/*
- cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
- mkdir mount
- sudo chmod a+rw /dev/loop0
- dd if=/dev/zero bs=512 count=2048 of=disk
- losetup /dev/loop0 disk
script:
# self-host test
- make -C littlefs-fuse
- littlefs-fuse/lfs --format /dev/loop0
- littlefs-fuse/lfs /dev/loop0 mount
- ls mount
- mkdir mount/littlefs
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs
- ls
- make -B test_dirs test_files QUIET=1
# Automatically update releases
- stage: deploy
env:
- STAGE=deploy
- NAME=deploy
script:
# Find version defined in lfs2.h
- LFS2_VERSION=$(grep -ox '#define LFS2_VERSION .*' lfs2.h | cut -d ' ' -f3)
- LFS2_VERSION_MAJOR=$((0xffff & ($LFS2_VERSION >> 16)))
- LFS2_VERSION_MINOR=$((0xffff & ($LFS2_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$LFS2_VERSION_MAJOR.$LFS2_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)
- LFS2_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL"
| jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g")
.captures[].string | tonumber) | max + 1'
|| echo 0)
# 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
- LFS2_VERSION="v$LFS2_VERSION_MAJOR.$LFS2_VERSION_MINOR.$LFS2_VERSION_PATCH"
- echo "VERSION $LFS2_VERSION"
- LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
- echo "VERSION $LFS_VERSION"
- |
# Check that we're the most recent commit
CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \
@@ -125,35 +155,24 @@ jobs:
| jq -re '.sha')
if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ]
then
# Create a simple tag
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs \
-d "{
\"ref\": \"refs/tags/$LFS2_VERSION\",
\"sha\": \"$TRAVIS_COMMIT\"
}"
# Minor release?
if [[ "$LFS2_VERSION" == *.0 ]]
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
if [ ! -z "$PREV" ]
then
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*.0" | head -1)
if [ ! -z "$PREV" ]
then
echo "PREV $PREV"
CHANGES=$'### Changes\n\n'$( \
git log --oneline $PREV.. --grep='^Merge' --invert-grep)
printf "CHANGES\n%s\n\n" "$CHANGES"
fi
# Create the release
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
-d "{
\"tag_name\": \"$LFS2_VERSION\",
\"name\": \"${LFS2_VERSION%.0}\",
\"draft\": true,
\"body\": $(jq -sR '.' <<< "$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
# Manage statuses

View File

@@ -1,6 +1,6 @@
TARGET = lfs2.a
TARGET = lfs.a
ifneq ($(wildcard test.c main.c),)
override TARGET = lfs2
override TARGET = lfs
endif
CC ?= gcc
@@ -25,8 +25,7 @@ ifdef WORD
override CFLAGS += -m$(WORD)
endif
override CFLAGS += -I.
override CFLAGS += -std=c99 -Wall -pedantic
override CFLAGS += -Wshadow -Wunused-parameter -Wjump-misses-init -Wsign-compare
override CFLAGS += -std=c99 -Wall -pedantic -Wshadow -Wunused-parameter
all: $(TARGET)
@@ -51,7 +50,7 @@ endif
-include $(DEP)
lfs2: $(OBJ)
lfs: $(OBJ)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
%.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:
``` c
#include "lfs2.h"
#include "lfs.h"
// variables used by the filesystem
lfs2_t lfs2;
lfs2_file_t file;
lfs_t lfs;
lfs_file_t file;
// configuration of the filesystem is provided by this struct
const struct lfs2_config cfg = {
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
@@ -49,37 +49,36 @@ const struct lfs2_config cfg = {
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.lookahead = 128,
};
// entry point
int main(void) {
// mount the filesystem
int err = lfs2_mount(&lfs2, &cfg);
int err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
lfs2_format(&lfs2, &cfg);
lfs2_mount(&lfs2, &cfg);
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
}
// read current count
uint32_t boot_count = 0;
lfs2_file_open(&lfs2, &file, "boot_count", LFS2_O_RDWR | LFS2_O_CREAT);
lfs2_file_read(&lfs2, &file, &boot_count, sizeof(boot_count));
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// update boot count
boot_count += 1;
lfs2_file_rewind(&lfs2, &file);
lfs2_file_write(&lfs2, &file, &boot_count, sizeof(boot_count));
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully
lfs2_file_close(&lfs2, &file);
lfs_file_close(&lfs, &file);
// release any resources we were using
lfs2_unmount(&lfs2);
lfs_unmount(&lfs);
// print the boot count
printf("boot_count: %d\n", boot_count);
@@ -89,7 +88,7 @@ int main(void) {
## Usage
Detailed documentation (or at least as much detail as is currently available)
can be found in the comments in [lfs2.h](lfs2.h).
can be found in the comments in [lfs.h](lfs.h).
As you may have noticed, littlefs takes in a configuration structure that
defines how the filesystem operates. The configuration struct provides the
@@ -97,9 +96,9 @@ filesystem with the block device operations and dimensions, tweakable
parameters that tradeoff memory usage for performance, and optional
static buffers if the user wants to avoid dynamic memory.
The state of the littlefs is stored in the `lfs2_t` type which is left up
The state of the littlefs is stored in the `lfs_t` type which is left up
to the user to allocate, allowing multiple filesystems to be in use
simultaneously. With the `lfs2_t` and configuration struct, a user can
simultaneously. With the `lfs_t` and configuration struct, a user can
format a block device or mount the filesystem.
Once mounted, the littlefs provides a full set of POSIX-like file and
@@ -113,11 +112,11 @@ filesystem until sync or close is called on the file.
## Other notes
All littlefs have the potential to return a negative error code. The errors
can be either one of those found in the `enum lfs2_error` in [lfs2.h](lfs2.h),
can be either one of those found in the `enum lfs_error` in [lfs.h](lfs.h),
or an error returned by the user's block device operations.
In the configuration struct, the `prog` and `erase` function provided by the
user may return a `LFS2_ERR_CORRUPT` error if the implementation already can
user may return a `LFS_ERR_CORRUPT` error if the implementation already can
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
integrity.
@@ -140,7 +139,7 @@ with all the nitty-gritty details. Can be useful for developing tooling.
## Testing
The littlefs comes with a test suite designed to run on a PC using the
[emulated block device](emubd/lfs2_emubd.h) found in the emubd directory.
[emulated block device](emubd/lfs_emubd.h) found in the emubd directory.
The tests assume a Linux environment and can be started with make:
``` bash
@@ -176,18 +175,3 @@ handy.
[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.
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.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "emubd/lfs2_emubd.h"
#include "emubd/lfs_emubd.h"
#include <errno.h>
#include <string.h>
@@ -20,42 +20,42 @@
// Emulated block device utils
static inline void lfs2_emubd_tole32(lfs2_emubd_t *emu) {
emu->cfg.read_size = lfs2_tole32(emu->cfg.read_size);
emu->cfg.prog_size = lfs2_tole32(emu->cfg.prog_size);
emu->cfg.block_size = lfs2_tole32(emu->cfg.block_size);
emu->cfg.block_count = lfs2_tole32(emu->cfg.block_count);
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 = lfs2_tole32(emu->stats.read_count);
emu->stats.prog_count = lfs2_tole32(emu->stats.prog_count);
emu->stats.erase_count = lfs2_tole32(emu->stats.erase_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 (unsigned i = 0; i < sizeof(emu->history.blocks) /
for (int i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs2_tole32(emu->history.blocks[i]);
emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]);
}
}
static inline void lfs2_emubd_fromle32(lfs2_emubd_t *emu) {
emu->cfg.read_size = lfs2_fromle32(emu->cfg.read_size);
emu->cfg.prog_size = lfs2_fromle32(emu->cfg.prog_size);
emu->cfg.block_size = lfs2_fromle32(emu->cfg.block_size);
emu->cfg.block_count = lfs2_fromle32(emu->cfg.block_count);
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 = lfs2_fromle32(emu->stats.read_count);
emu->stats.prog_count = lfs2_fromle32(emu->stats.prog_count);
emu->stats.erase_count = lfs2_fromle32(emu->stats.erase_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 (unsigned i = 0; i < sizeof(emu->history.blocks) /
for (int i = 0; i < sizeof(emu->history.blocks) /
sizeof(emu->history.blocks[0]); i++) {
emu->history.blocks[i] = lfs2_fromle32(emu->history.blocks[i]);
emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
}
}
// Block device emulated on existing filesystem
int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path) {
lfs2_emubd_t *emu = cfg->context;
int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
lfs_emubd_t *emu = cfg->context;
emu->cfg.read_size = cfg->read_size;
emu->cfg.prog_size = cfg->prog_size;
emu->cfg.block_size = cfg->block_size;
@@ -63,7 +63,7 @@ int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path) {
// Allocate buffer for creating children files
size_t pathlen = strlen(path);
emu->path = malloc(pathlen + 1 + LFS2_NAME_MAX + 1);
emu->path = malloc(pathlen + 1 + LFS_NAME_MAX + 1);
if (!emu->path) {
return -ENOMEM;
}
@@ -71,7 +71,7 @@ int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path) {
strcpy(emu->path, path);
emu->path[pathlen] = '/';
emu->child = &emu->path[pathlen+1];
memset(emu->child, '\0', LFS2_NAME_MAX+1);
memset(emu->child, '\0', LFS_NAME_MAX+1);
// Create directory if it doesn't exist
int err = mkdir(path, 0777);
@@ -80,13 +80,13 @@ int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path) {
}
// Load stats to continue incrementing
snprintf(emu->child, LFS2_NAME_MAX, ".stats");
snprintf(emu->child, LFS_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);
lfs2_emubd_fromle32(emu);
lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
@@ -98,13 +98,13 @@ int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path) {
}
// Load history
snprintf(emu->child, LFS2_NAME_MAX, ".history");
snprintf(emu->child, LFS_NAME_MAX, ".history");
f = fopen(emu->path, "r");
if (!f) {
memset(&emu->history, 0, sizeof(emu->history));
} else {
size_t res = fread(&emu->history, sizeof(emu->history), 1, f);
lfs2_emubd_fromle32(emu);
lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
@@ -118,16 +118,16 @@ int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path) {
return 0;
}
void lfs2_emubd_destroy(const struct lfs2_config *cfg) {
lfs2_emubd_sync(cfg);
void lfs_emubd_destroy(const struct lfs_config *cfg) {
lfs_emubd_sync(cfg);
lfs2_emubd_t *emu = cfg->context;
lfs_emubd_t *emu = cfg->context;
free(emu->path);
}
int lfs2_emubd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size) {
lfs2_emubd_t *emu = cfg->context;
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
lfs_emubd_t *emu = cfg->context;
uint8_t *data = buffer;
// Check if read is valid
@@ -139,7 +139,7 @@ int lfs2_emubd_read(const struct lfs2_config *cfg, lfs2_block_t block,
memset(data, 0, size);
// Read data
snprintf(emu->child, LFS2_NAME_MAX, "%" PRIx32, block);
snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
FILE *f = fopen(emu->path, "rb");
if (!f && errno != ENOENT) {
@@ -167,9 +167,9 @@ int lfs2_emubd_read(const struct lfs2_config *cfg, lfs2_block_t block,
return 0;
}
int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size) {
lfs2_emubd_t *emu = cfg->context;
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
lfs_emubd_t *emu = cfg->context;
const uint8_t *data = buffer;
// Check if write is valid
@@ -178,7 +178,7 @@ int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
assert(block < cfg->block_count);
// Program data
snprintf(emu->child, LFS2_NAME_MAX, "%" PRIx32, block);
snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
FILE *f = fopen(emu->path, "r+b");
if (!f) {
@@ -225,14 +225,14 @@ int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
return 0;
}
int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
lfs2_emubd_t *emu = cfg->context;
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
lfs_emubd_t *emu = cfg->context;
// Check if erase is valid
assert(block < cfg->block_count);
// Erase the block
snprintf(emu->child, LFS2_NAME_MAX, "%" PRIx32, block);
snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
struct stat st;
int err = stat(emu->path, &st);
if (err && errno != ENOENT) {
@@ -262,19 +262,19 @@ int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
return 0;
}
int lfs2_emubd_sync(const struct lfs2_config *cfg) {
lfs2_emubd_t *emu = cfg->context;
int lfs_emubd_sync(const struct lfs_config *cfg) {
lfs_emubd_t *emu = cfg->context;
// Just write out info/stats for later lookup
snprintf(emu->child, LFS2_NAME_MAX, ".config");
snprintf(emu->child, LFS_NAME_MAX, ".config");
FILE *f = fopen(emu->path, "w");
if (!f) {
return -errno;
}
lfs2_emubd_tole32(emu);
lfs_emubd_tole32(emu);
size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f);
lfs2_emubd_fromle32(emu);
lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
@@ -284,15 +284,15 @@ int lfs2_emubd_sync(const struct lfs2_config *cfg) {
return -errno;
}
snprintf(emu->child, LFS2_NAME_MAX, ".stats");
snprintf(emu->child, LFS_NAME_MAX, ".stats");
f = fopen(emu->path, "w");
if (!f) {
return -errno;
}
lfs2_emubd_tole32(emu);
lfs_emubd_tole32(emu);
res = fwrite(&emu->stats, sizeof(emu->stats), 1, f);
lfs2_emubd_fromle32(emu);
lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
@@ -302,15 +302,15 @@ int lfs2_emubd_sync(const struct lfs2_config *cfg) {
return -errno;
}
snprintf(emu->child, LFS2_NAME_MAX, ".history");
snprintf(emu->child, LFS_NAME_MAX, ".history");
f = fopen(emu->path, "w");
if (!f) {
return -errno;
}
lfs2_emubd_tole32(emu);
lfs_emubd_tole32(emu);
res = fwrite(&emu->history, sizeof(emu->history), 1, f);
lfs2_emubd_fromle32(emu);
lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}

View File

@@ -4,11 +4,11 @@
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_EMUBD_H
#define LFS2_EMUBD_H
#ifndef LFS_EMUBD_H
#define LFS_EMUBD_H
#include "lfs2.h"
#include "lfs2_util.h"
#include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus
extern "C"
@@ -17,25 +17,25 @@ extern "C"
// Config options
#ifndef LFS2_EMUBD_READ_SIZE
#define LFS2_EMUBD_READ_SIZE 1
#ifndef LFS_EMUBD_READ_SIZE
#define LFS_EMUBD_READ_SIZE 1
#endif
#ifndef LFS2_EMUBD_PROG_SIZE
#define LFS2_EMUBD_PROG_SIZE 1
#ifndef LFS_EMUBD_PROG_SIZE
#define LFS_EMUBD_PROG_SIZE 1
#endif
#ifndef LFS2_EMUBD_ERASE_SIZE
#define LFS2_EMUBD_ERASE_SIZE 512
#ifndef LFS_EMUBD_ERASE_SIZE
#define LFS_EMUBD_ERASE_SIZE 512
#endif
#ifndef LFS2_EMUBD_TOTAL_SIZE
#define LFS2_EMUBD_TOTAL_SIZE 524288
#ifndef LFS_EMUBD_TOTAL_SIZE
#define LFS_EMUBD_TOTAL_SIZE 524288
#endif
// The emu bd state
typedef struct lfs2_emubd {
typedef struct lfs_emubd {
char *path;
char *child;
@@ -46,7 +46,7 @@ typedef struct lfs2_emubd {
} stats;
struct {
lfs2_block_t blocks[4];
lfs_block_t blocks[4];
} history;
struct {
@@ -55,33 +55,33 @@ typedef struct lfs2_emubd {
uint32_t block_size;
uint32_t block_count;
} cfg;
} lfs2_emubd_t;
} lfs_emubd_t;
// Create a block device using path for the directory to store blocks
int lfs2_emubd_create(const struct lfs2_config *cfg, const char *path);
int lfs_emubd_create(const struct lfs_config *cfg, const char *path);
// Clean up memory associated with emu block device
void lfs2_emubd_destroy(const struct lfs2_config *cfg);
void lfs_emubd_destroy(const struct lfs_config *cfg);
// Read a block
int lfs2_emubd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size);
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block);
// Sync the block device
int lfs2_emubd_sync(const struct lfs2_config *cfg);
int lfs_emubd_sync(const struct lfs_config *cfg);
#ifdef __cplusplus

3423
lfs.c Normal file

File diff suppressed because it is too large Load Diff

661
lfs.h Normal file
View File

@@ -0,0 +1,661 @@
/*
* 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 = 0x001,
LFS_TYPE_DIR = 0x002,
// internally used types
LFS_TYPE_USER = 0x100,
LFS_TYPE_SUPERBLOCK = 0x011,
LFS_TYPE_ROOT = 0x012,
LFS_TYPE_NAME = 0x000,
LFS_TYPE_DELETE = 0x030,
LFS_TYPE_STRUCT = 0x040,
LFS_TYPE_GLOBALS = 0x080,
LFS_TYPE_TAIL = 0x0c0,
LFS_TYPE_SOFTTAIL = 0x0c0,
LFS_TYPE_HARDTAIL = 0x0c1,
LFS_TYPE_CRC = 0x0f0,
LFS_TYPE_DIRSTRUCT = 0x040,
LFS_TYPE_INLINESTRUCT = 0x041,
LFS_TYPE_CTZSTRUCT = 0x042,
// internal chip sources
LFS_FROM_REGION = 0x000,
LFS_FROM_DISK = 0x200,
LFS_FROM_MOVE = 0x050,
LFS_FROM_ATTRS = 0x060,
LFS_FROM_SUPERBLOCK = 0x070,
};
// 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;
bool deorphaned;
} s;
} 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);
// Get custom attributes on the filesystem
//
// 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.
//
// Note, filesystem-level attributes are not available for wear-leveling
//
// Returns the size of the attribute, or a negative error code on failure.
// Note, the returned size is the size of the attribute on disk, irrespective
// of the size of the buffer. This can be used to dynamically allocate a buffer
// or check for existance.
lfs_ssize_t lfs_fs_getattr(lfs_t *lfs,
uint8_t type, void *buffer, lfs_size_t size);
// Set custom attributes on the filesystem
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be
// implicitly created, and setting the size of an attribute to zero deletes
// the attribute.
//
// Note, filesystem-level attributes are not available for wear-leveling
//
// Returns a negative error code on failure.
int lfs_fs_setattr(lfs_t *lfs,
uint8_t type, const void *buffer, lfs_size_t size);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

3794
lfs2.c

File diff suppressed because it is too large Load Diff

625
lfs2.h
View File

@@ -1,625 +0,0 @@
/*
* The little filesystem
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_H
#define LFS2_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 LFS2_VERSION 0x00020000
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
// Version of On-disk data structures
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS2_DISK_VERSION 0x00020000
#define LFS2_DISK_VERSION_MAJOR (0xffff & (LFS2_DISK_VERSION >> 16))
#define LFS2_DISK_VERSION_MINOR (0xffff & (LFS2_DISK_VERSION >> 0))
/// Definitions ///
// Type definitions
typedef uint32_t lfs2_size_t;
typedef uint32_t lfs2_off_t;
typedef int32_t lfs2_ssize_t;
typedef int32_t lfs2_soff_t;
typedef uint32_t lfs2_block_t;
// Maximum name size in bytes, may be redefined to reduce the size of the
// info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers.
#ifndef LFS2_NAME_MAX
#define LFS2_NAME_MAX 255
#endif
// Maximum size of a file in bytes, may be redefined to limit to support other
// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
// functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS2_FILE_MAX
#define LFS2_FILE_MAX 2147483647
#endif
// Maximum size of custom attributes in bytes, may be redefined, but there is
// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022.
#ifndef LFS2_ATTR_MAX
#define LFS2_ATTR_MAX 1022
#endif
// Possible error codes, these are negative to allow
// valid positive return values
enum lfs2_error {
LFS2_ERR_OK = 0, // No error
LFS2_ERR_IO = -5, // Error during device operation
LFS2_ERR_CORRUPT = -84, // Corrupted
LFS2_ERR_NOENT = -2, // No directory entry
LFS2_ERR_EXIST = -17, // Entry already exists
LFS2_ERR_NOTDIR = -20, // Entry is not a dir
LFS2_ERR_ISDIR = -21, // Entry is a dir
LFS2_ERR_NOTEMPTY = -39, // Dir is not empty
LFS2_ERR_BADF = -9, // Bad file number
LFS2_ERR_FBIG = -27, // File too large
LFS2_ERR_INVAL = -22, // Invalid parameter
LFS2_ERR_NOSPC = -28, // No space left on device
LFS2_ERR_NOMEM = -12, // No more memory available
LFS2_ERR_NOATTR = -61, // No data/attr available
LFS2_ERR_NAMETOOLONG = -36, // File name too long
};
// File types
enum lfs2_type {
// file types
LFS2_TYPE_REG = 0x001,
LFS2_TYPE_DIR = 0x002,
// internally used types
LFS2_TYPE_SPLICE = 0x400,
LFS2_TYPE_NAME = 0x000,
LFS2_TYPE_STRUCT = 0x200,
LFS2_TYPE_USERATTR = 0x300,
LFS2_TYPE_FROM = 0x100,
LFS2_TYPE_TAIL = 0x600,
LFS2_TYPE_GLOBALS = 0x700,
LFS2_TYPE_CRC = 0x500,
// internally used type specializations
LFS2_TYPE_CREATE = 0x401,
LFS2_TYPE_DELETE = 0x4ff,
LFS2_TYPE_SUPERBLOCK = 0x0ff,
LFS2_TYPE_DIRSTRUCT = 0x200,
LFS2_TYPE_CTZSTRUCT = 0x202,
LFS2_TYPE_INLINESTRUCT = 0x201,
LFS2_TYPE_SOFTTAIL = 0x600,
LFS2_TYPE_HARDTAIL = 0x601,
LFS2_TYPE_MOVESTATE = 0x7ff,
// internal chip sources
LFS2_FROM_NOOP = 0x000,
LFS2_FROM_MOVE = 0x101,
LFS2_FROM_USERATTRS = 0x102,
};
// File open flags
enum lfs2_open_flags {
// open flags
LFS2_O_RDONLY = 1, // Open a file as read only
LFS2_O_WRONLY = 2, // Open a file as write only
LFS2_O_RDWR = 3, // Open a file as read and write
LFS2_O_CREAT = 0x0100, // Create a file if it does not exist
LFS2_O_EXCL = 0x0200, // Fail if a file already exists
LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS2_O_APPEND = 0x0800, // Move to end of file on every write
// internally used flags
LFS2_F_DIRTY = 0x010000, // File does not match storage
LFS2_F_WRITING = 0x020000, // File has been written since last flush
LFS2_F_READING = 0x040000, // File has been read since last flush
LFS2_F_ERRED = 0x080000, // An error occured during write
LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry
};
// File seek flags
enum lfs2_whence_flags {
LFS2_SEEK_SET = 0, // Seek relative to an absolute position
LFS2_SEEK_CUR = 1, // Seek relative to the current file position
LFS2_SEEK_END = 2, // Seek relative to the end of the file
};
// Configuration provided during initialization of the littlefs
struct lfs2_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 lfs2_config *c, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_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 LFS2_ERR_CORRUPT if the block should be considered bad.
int (*prog)(const struct lfs2_config *c, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propogated to the user.
// May return LFS2_ERR_CORRUPT if the block should be considered bad.
int (*erase)(const struct lfs2_config *c, lfs2_block_t block);
// Sync the state of the underlying block device. Negative error codes
// are propogated to the user.
int (*sync)(const struct lfs2_config *c);
// Minimum size of a block read. All read operations will be a
// multiple of this value.
lfs2_size_t read_size;
// Minimum size of a block program. All program operations will be a
// multiple of this value.
lfs2_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, non-inlined files
// take up at minimum one block. Must be a multiple of the read
// and program sizes.
lfs2_size_t block_size;
// Number of erasable blocks on the device.
lfs2_size_t block_count;
// Number of erase cycles before we should move data to another block.
// May be zero, 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.
// The littlefs needs a read cache, a program cache, and one additional
// cache per file. Larger caches can improve performance by storing more
// data and reducing the number of disk accesses. Must be a multiple of
// the read and program sizes, and a factor of the block size.
lfs2_size_t cache_size;
// Size of the lookahead buffer in bytes. A larger lookahead buffer
// increases the number of blocks found during an allocation pass. The
// lookahead buffer is stored as a compact bitmap, so each byte of RAM
// can track 8 blocks. Must be a multiple of 4.
lfs2_size_t lookahead_size;
// Optional statically allocated read buffer. Must be cache_size.
// By default lfs2_malloc is used to allocate this buffer.
void *read_buffer;
// Optional statically allocated program buffer. Must be cache_size.
// By default lfs2_malloc is used to allocate this buffer.
void *prog_buffer;
// Optional statically allocated program buffer. Must be lookahead_size.
// By default lfs2_malloc is used to allocate this buffer.
void *lookahead_buffer;
// 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 LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in
// superblock and must be respected by other littlefs drivers.
lfs2_size_t name_max;
// Optional upper limit on files in bytes. No downside for larger files
// but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored
// in superblock and must be respected by other littlefs drivers.
lfs2_size_t file_max;
// Optional upper limit on custom attributes in bytes. No downside for
// larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to
// LFS2_ATTR_MAX when zero.
lfs2_size_t attr_max;
};
// File info structure
struct lfs2_info {
// Type of the file, either LFS2_TYPE_REG or LFS2_TYPE_DIR
uint8_t type;
// Size of the file, only valid for REG files. Limited to 32-bits.
lfs2_size_t size;
// Name of the file stored as a null-terminated string. Limited to
// LFS2_NAME_MAX+1, which can be changed by redefining LFS2_NAME_MAX to
// reduce RAM. LFS2_NAME_MAX is stored in superblock and must be
// respected by other littlefs drivers.
char name[LFS2_NAME_MAX+1];
};
// Custom attribute structure, used to describe custom attributes
// committed atomically during file writes.
struct lfs2_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 LFS2_ATTR_MAX
lfs2_size_t size;
};
// Optional configuration provided during lfs2_file_opencfg
struct lfs2_file_config {
// Optional statically allocated file buffer. Must be cache_size.
// By default lfs2_malloc is used to allocate this buffer.
void *buffer;
// Optional list of custom attributes related to the file. If the file
// is opened with read access, these attributes will be read from disk
// during the open call. If the file is opened with write access, the
// attributes will be written to disk every file sync or close. This
// write occurs atomically with update to the file's contents.
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS2_ATTR_MAX bytes. When read, if the stored attribute is smaller
// than the buffer, it will be padded with zeros. If the stored attribute
// is larger, then it will be silently truncated. If the attribute is not
// found, it will be created implicitly.
struct lfs2_attr *attrs;
// Number of custom attributes in the list
lfs2_size_t attr_count;
};
/// internal littlefs data structures ///
typedef struct lfs2_cache {
lfs2_block_t block;
lfs2_off_t off;
lfs2_size_t size;
uint8_t *buffer;
} lfs2_cache_t;
typedef struct lfs2_mdir {
lfs2_block_t pair[2];
uint32_t rev;
lfs2_off_t off;
uint32_t etag;
uint16_t count;
bool erased;
bool split;
lfs2_block_t tail[2];
} lfs2_mdir_t;
// littlefs directory type
typedef struct lfs2_dir {
struct lfs2_dir *next;
uint16_t id;
uint8_t type;
lfs2_mdir_t m;
lfs2_off_t pos;
lfs2_block_t head[2];
} lfs2_dir_t;
// littlefs file type
typedef struct lfs2_file {
struct lfs2_file *next;
uint16_t id;
uint8_t type;
lfs2_mdir_t m;
struct lfs2_ctz {
lfs2_block_t head;
lfs2_size_t size;
} ctz;
uint32_t flags;
lfs2_off_t pos;
lfs2_block_t block;
lfs2_off_t off;
lfs2_cache_t cache;
const struct lfs2_file_config *cfg;
} lfs2_file_t;
typedef struct lfs2_superblock {
uint32_t version;
lfs2_size_t block_size;
lfs2_size_t block_count;
lfs2_size_t name_max;
lfs2_size_t file_max;
lfs2_size_t attr_max;
} lfs2_superblock_t;
// The littlefs filesystem type
typedef struct lfs2 {
lfs2_cache_t rcache;
lfs2_cache_t pcache;
lfs2_block_t root[2];
struct lfs2_mlist {
struct lfs2_mlist *next;
uint16_t id;
uint8_t type;
lfs2_mdir_t m;
} *mlist;
uint32_t seed;
struct lfs2_gstate {
uint32_t tag;
lfs2_block_t pair[2];
} gstate, gpending, gdelta;
struct lfs2_free {
lfs2_block_t off;
lfs2_block_t size;
lfs2_block_t i;
lfs2_block_t ack;
uint32_t *buffer;
} free;
const struct lfs2_config *cfg;
lfs2_size_t name_max;
lfs2_size_t file_max;
lfs2_size_t attr_max;
} lfs2_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 lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config);
// Mounts a littlefs
//
// Requires a littlefs object and config struct. Multiple filesystems
// may be mounted simultaneously with multiple littlefs objects. Both
// lfs2 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 lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *config);
// Unmounts a littlefs
//
// Does nothing besides releasing any allocated resources.
// Returns a negative error code on failure.
int lfs2_unmount(lfs2_t *lfs2);
/// General operations ///
// Removes a file or directory
//
// If removing a directory, the directory must be empty.
// Returns a negative error code on failure.
int lfs2_remove(lfs2_t *lfs2, 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 lfs2_rename(lfs2_t *lfs2, 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 lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info);
// Get a custom attribute
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS2_ATTR_MAX bytes. When read, if the stored attribute is smaller than
// the buffer, it will be padded with zeros. If the stored attribute is larger,
// then it will be silently truncated. If no attribute is found, the error
// LFS2_ERR_NOATTR is returned and the buffer is filled with zeros.
//
// Returns the size of the attribute, or a negative error code on failure.
// 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.
lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path,
uint8_t type, void *buffer, lfs2_size_t size);
// Set custom attributes
//
// Custom attributes are uniquely identified by an 8-bit type and limited
// to LFS2_ATTR_MAX bytes. If an attribute is not found, it will be
// implicitly created.
//
// Returns a negative error code on failure.
int lfs2_setattr(lfs2_t *lfs2, const char *path,
uint8_t type, const void *buffer, lfs2_size_t size);
// Removes a custom attribute
//
// If an attribute is not found, nothing happens.
//
// Returns a negative error code on failure.
int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type);
/// File operations ///
// Open a file
//
// The mode that the file is opened in is determined by the flags, which
// are values from the enum lfs2_open_flags that are bitwise-ored together.
//
// Returns a negative error code on failure.
int lfs2_file_open(lfs2_t *lfs2, lfs2_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 lfs2_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 lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file,
const char *path, int flags,
const struct lfs2_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 lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file);
// Synchronize a file on storage
//
// Any pending writes are written out to storage.
// Returns a negative error code on failure.
int lfs2_file_sync(lfs2_t *lfs2, lfs2_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.
lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file,
void *buffer, lfs2_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.
lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file,
const void *buffer, lfs2_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.
lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file,
lfs2_soff_t off, int whence);
// Truncates the size of the file to the specified size
//
// Returns a negative error code on failure.
int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size);
// Return the position of the file
//
// Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_CUR)
// Returns the position of the file, or a negative error code on failure.
lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file);
// Change the position of the file to the beginning of the file
//
// Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_CUR)
// Returns a negative error code on failure.
int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file);
// Return the size of the file
//
// Similar to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_END)
// Returns the size of the file, or a negative error code on failure.
lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file);
/// Directory operations ///
// Create a directory
//
// Returns a negative error code on failure.
int lfs2_mkdir(lfs2_t *lfs2, 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 lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path);
// Close a directory
//
// Releases any allocated resources.
// Returns a negative error code on failure.
int lfs2_dir_close(lfs2_t *lfs2, lfs2_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 lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_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 lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_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.
lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir);
// Change the position of the directory to the beginning of the directory
//
// Returns a negative error code on failure.
int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_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.
lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2);
// 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 lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -1,17 +1,17 @@
/*
* lfs2 util functions
* lfs util functions
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "lfs2_util.h"
#include "lfs_util.h"
// Only compile if user does not provide custom config
#ifndef LFS2_CONFIG
#ifndef LFS_CONFIG
// Software CRC implementation with small lookup table
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
uint32_t lfs_crc32(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,

View File

@@ -1,22 +1,22 @@
/*
* lfs2 utility functions
* lfs utility functions
*
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_UTIL_H
#define LFS2_UTIL_H
#ifndef LFS_UTIL_H
#define LFS_UTIL_H
// Users can override lfs2_util.h with their own configuration by defining
// LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.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 LFS2_CONFIG is used, none of the default utils will be emitted and must be
// provided by the config file. To start, I would suggest copying lfs2_util.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 LFS2_CONFIG
#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
#define LFS2_STRINGIZE2(x) #x
#include LFS2_STRINGIZE(LFS2_CONFIG)
#ifdef LFS_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG)
#else
// System includes
@@ -25,13 +25,13 @@
#include <string.h>
#include <inttypes.h>
#ifndef LFS2_NO_MALLOC
#ifndef LFS_NO_MALLOC
#include <stdlib.h>
#endif
#ifndef LFS2_NO_ASSERT
#ifndef LFS_NO_ASSERT
#include <assert.h>
#endif
#if !defined(LFS2_NO_DEBUG) || !defined(LFS2_NO_WARN) || !defined(LFS2_NO_ERROR)
#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR)
#include <stdio.h>
#endif
@@ -46,60 +46,60 @@ extern "C"
// code footprint
// Logging functions
#ifndef LFS2_NO_DEBUG
#define LFS2_DEBUG(fmt, ...) \
printf("lfs2 debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#ifndef LFS_NO_DEBUG
#define LFS_DEBUG(fmt, ...) \
printf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS2_DEBUG(fmt, ...)
#define LFS_DEBUG(fmt, ...)
#endif
#ifndef LFS2_NO_WARN
#define LFS2_WARN(fmt, ...) \
printf("lfs2 warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#ifndef LFS_NO_WARN
#define LFS_WARN(fmt, ...) \
printf("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS2_WARN(fmt, ...)
#define LFS_WARN(fmt, ...)
#endif
#ifndef LFS2_NO_ERROR
#define LFS2_ERROR(fmt, ...) \
printf("lfs2 error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#ifndef LFS_NO_ERROR
#define LFS_ERROR(fmt, ...) \
printf("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
#else
#define LFS2_ERROR(fmt, ...)
#define LFS_ERROR(fmt, ...)
#endif
// Runtime assertions
#ifndef LFS2_NO_ASSERT
#define LFS2_ASSERT(test) assert(test)
#ifndef LFS_NO_ASSERT
#define LFS_ASSERT(test) assert(test)
#else
#define LFS2_ASSERT(test)
#define LFS_ASSERT(test)
#endif
// Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS2_NO_INTRINSICS falls back to a more
// 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 lfs2_max(uint32_t a, uint32_t b) {
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b;
}
static inline uint32_t lfs2_min(uint32_t a, uint32_t 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 lfs2_aligndown(uint32_t a, uint32_t alignment) {
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
return a - (a % alignment);
}
static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) {
return lfs2_aligndown(a + alignment-1, 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 lfs2_npw2(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
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;
@@ -114,18 +114,18 @@ static inline uint32_t lfs2_npw2(uint32_t a) {
}
// Count the number of trailing binary zeros in a
// lfs2_ctz(0) may be undefined
static inline uint32_t lfs2_ctz(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && defined(__GNUC__)
// 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 lfs2_npw2((a & -a) + 1) - 1;
return lfs_npw2((a & -a) + 1) - 1;
#endif
}
// Count the number of binary ones in a
static inline uint32_t lfs2_popc(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
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);
@@ -136,18 +136,18 @@ static inline uint32_t lfs2_popc(uint32_t a) {
// Find the sequence comparison of a and b, this is the distance
// between a and b ignoring overflow
static inline int lfs2_scmp(uint32_t a, uint32_t b) {
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 lfs2_fromle32(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && ( \
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(LFS2_NO_INTRINSICS) && ( \
#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__))
@@ -160,40 +160,38 @@ static inline uint32_t lfs2_fromle32(uint32_t a) {
#endif
}
static inline uint32_t lfs2_tole32(uint32_t a) {
return lfs2_fromle32(a);
static inline uint32_t lfs_tole32(uint32_t a) {
return lfs_fromle32(a);
}
// Convert between 32-bit big-endian and native order
static inline uint32_t lfs2_frombe32(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && ( \
// 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 __builtin_bswap32(a);
#elif !defined(LFS2_NO_INTRINSICS) && ( \
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 a;
return __builtin_bswap16(a);
#else
return (((uint8_t*)&a)[0] << 24) |
(((uint8_t*)&a)[1] << 16) |
(((uint8_t*)&a)[2] << 8) |
(((uint8_t*)&a)[3] << 0);
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8);
#endif
}
static inline uint32_t lfs2_tobe32(uint32_t a) {
return lfs2_frombe32(a);
static inline uint16_t lfs_tole16(uint16_t a) {
return lfs_fromle16(a);
}
// Calculate CRC-32 with polynomial = 0x04c11db7
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size);
uint32_t lfs_crc32(uint32_t crc, const void *buffer, size_t size);
// Allocate memory, only used if buffers are not provided to littlefs
static inline void *lfs2_malloc(size_t size) {
#ifndef LFS2_NO_MALLOC
static inline void *lfs_malloc(size_t size) {
#ifndef LFS_NO_MALLOC
return malloc(size);
#else
(void)size;
@@ -202,8 +200,8 @@ static inline void *lfs2_malloc(size_t size) {
}
// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs2_free(void *p) {
#ifndef LFS2_NO_MALLOC
static inline void lfs_free(void *p) {
#ifndef LFS_NO_MALLOC
free(p);
#else
(void)p;

View File

@@ -1,61 +0,0 @@
#!/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 lfs22
import os
import os.path
import re
import glob
import itertools
import tempfile
import shutil
import subprocess
DEFAULT_PREFIX = "lfs2"
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

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

View File

@@ -4,35 +4,30 @@ import struct
import binascii
TYPES = {
(0x700, 0x400): 'splice',
(0x7ff, 0x401): 'create',
(0x7ff, 0x4ff): 'delete',
(0x700, 0x000): 'name',
(0x7ff, 0x001): 'name reg',
(0x7ff, 0x002): 'name dir',
(0x7ff, 0x0ff): 'name superblock',
(0x700, 0x200): 'struct',
(0x7ff, 0x200): 'struct dir',
(0x7ff, 0x202): 'struct ctz',
(0x7ff, 0x201): 'struct inline',
(0x700, 0x300): 'userattr',
(0x700, 0x600): 'tail',
(0x7ff, 0x600): 'tail soft',
(0x7ff, 0x601): 'tail hard',
(0x700, 0x700): 'gstate',
(0x7ff, 0x7ff): 'gstate move',
(0x700, 0x500): 'crc',
(0x1ff, 0x001): 'reg',
(0x1ff, 0x002): 'dir',
(0x1ff, 0x011): 'superblock',
(0x1ff, 0x012): 'root',
(0x1ff, 0x030): 'delete',
(0x1f0, 0x080): 'globals',
(0x1ff, 0x0c0): 'tail soft',
(0x1ff, 0x0c1): 'tail hard',
(0x1ff, 0x0f0): 'crc',
(0x1ff, 0x040): 'struct dir',
(0x1ff, 0x041): 'struct inline',
(0x1ff, 0x042): 'struct ctz',
(0x100, 0x100): 'attr',
}
def typeof(type):
for prefix in range(12):
mask = 0x7ff & ~((1 << prefix)-1)
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))
' [%0*x]' % (prefix/4, type & ((1 << prefix)-1))
if prefix else '')
else:
return '%02x' % type
return '[%02x]' % type
def main(*blocks):
# find most recent block
@@ -55,58 +50,49 @@ def main(*blocks):
crc = ncrc
versions.append((nrev, '%s (rev %d)' % (block, nrev)))
except (IOError, struct.error):
except IOError:
pass
if not file:
print 'Bad metadata pair {%s}' % ', '.join(blocks)
return 1
print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True))
# go through each tag, print useful information
print "%-4s %-8s %-14s %3s %4s %s" % (
print "%-4s %-8s %-14s %3s %3s %s" % (
'off', 'tag', 'type', 'id', 'len', 'dump')
tag = 0xffffffff
tag = 0
off = 4
while True:
try:
data = file.read(4)
crc = binascii.crc32(data, crc)
ntag, = struct.unpack('>I', data)
ntag, = struct.unpack('<I', data)
except struct.error:
break
tag ^= ntag
off += 4
type = (tag & 0x7ff00000) >> 20
id = (tag & 0x000ffc00) >> 10
size = (tag & 0x000003ff) >> 0
iscrc = (type & 0x700) == 0x500
type = (tag & 0x7fc00000) >> 22
id = (tag & 0x003ff000) >> 12
size = (tag & 0x00000fff) >> 0
data = file.read(size if size != 0x3ff else 0)
if iscrc:
data = file.read(size)
if type == 0x0f0:
crc = binascii.crc32(data[:4], crc)
else:
crc = binascii.crc32(data, crc)
print '%04x: %08x %-15s %3s %4s %-23s %-8s' % (
print '%04x: %08x %-14s %3s %3d %-23s %-8s' % (
off, tag,
typeof(type) + (' bad!' if iscrc and ~crc else ''),
id if id != 0x3ff else '.',
size if size != 0x3ff else 'x',
typeof(type) + (' bad!' if type == 0x0f0 and ~crc else ''),
id if id != 0x3ff else '.', size,
' '.join('%02x' % ord(c) for c in data[:8]),
''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8]))
off += size if size != 0x3ff else 0
if iscrc:
off += tag & 0xfff
if type == 0x0f0:
crc = 0
tag ^= (type & 1) << 31
return 0
if __name__ == "__main__":
import sys
sys.exit(main(*sys.argv[1:]))
main(*sys.argv[1:])

View File

@@ -1,6 +1,6 @@
/// AUTOGENERATED TEST ///
#include "lfs2.h"
#include "emubd/lfs2_emubd.h"
#include "lfs.h"
#include "emubd/lfs_emubd.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -37,7 +37,7 @@ static void test_assert(const char *file, unsigned line,
// utility functions for traversals
static int __attribute__((used)) test_count(void *p, lfs2_block_t b) {{
static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{
(void)b;
unsigned *u = (unsigned*)p;
*u += 1;
@@ -45,72 +45,72 @@ static int __attribute__((used)) test_count(void *p, lfs2_block_t b) {{
}}
// lfs2 declarations
lfs2_t lfs2;
lfs2_emubd_t bd;
lfs2_file_t file[4];
lfs2_dir_t dir[4];
struct lfs2_info info;
// lfs declarations
lfs_t lfs;
lfs_emubd_t bd;
lfs_file_t file[4];
lfs_dir_t dir[4];
struct lfs_info info;
uint8_t buffer[1024];
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_size_t size;
lfs2_size_t wsize;
lfs2_size_t rsize;
lfs_size_t size;
lfs_size_t wsize;
lfs_size_t rsize;
uintmax_t test;
#ifndef LFS2_READ_SIZE
#define LFS2_READ_SIZE 16
#ifndef LFS_READ_SIZE
#define LFS_READ_SIZE 16
#endif
#ifndef LFS2_PROG_SIZE
#define LFS2_PROG_SIZE LFS2_READ_SIZE
#ifndef LFS_PROG_SIZE
#define LFS_PROG_SIZE LFS_READ_SIZE
#endif
#ifndef LFS2_BLOCK_SIZE
#define LFS2_BLOCK_SIZE 512
#ifndef LFS_BLOCK_SIZE
#define LFS_BLOCK_SIZE 512
#endif
#ifndef LFS2_BLOCK_COUNT
#define LFS2_BLOCK_COUNT 1024
#ifndef LFS_BLOCK_COUNT
#define LFS_BLOCK_COUNT 1024
#endif
#ifndef LFS2_BLOCK_CYCLES
#define LFS2_BLOCK_CYCLES 1024
#ifndef LFS_BLOCK_CYCLES
#define LFS_BLOCK_CYCLES 1024
#endif
#ifndef LFS2_CACHE_SIZE
#define LFS2_CACHE_SIZE 64
#ifndef LFS_CACHE_SIZE
#define LFS_CACHE_SIZE 64
#endif
#ifndef LFS2_LOOKAHEAD_SIZE
#define LFS2_LOOKAHEAD_SIZE 16
#ifndef LFS_LOOKAHEAD
#define LFS_LOOKAHEAD 128
#endif
const struct lfs2_config cfg = {{
const struct lfs_config cfg = {{
.context = &bd,
.read = &lfs2_emubd_read,
.prog = &lfs2_emubd_prog,
.erase = &lfs2_emubd_erase,
.sync = &lfs2_emubd_sync,
.read = &lfs_emubd_read,
.prog = &lfs_emubd_prog,
.erase = &lfs_emubd_erase,
.sync = &lfs_emubd_sync,
.read_size = LFS2_READ_SIZE,
.prog_size = LFS2_PROG_SIZE,
.block_size = LFS2_BLOCK_SIZE,
.block_count = LFS2_BLOCK_COUNT,
.block_cycles = LFS2_BLOCK_CYCLES,
.cache_size = LFS2_CACHE_SIZE,
.lookahead_size = LFS2_LOOKAHEAD_SIZE,
.read_size = LFS_READ_SIZE,
.prog_size = LFS_PROG_SIZE,
.block_size = LFS_BLOCK_SIZE,
.block_count = LFS_BLOCK_COUNT,
.block_cycles = LFS_BLOCK_CYCLES,
.cache_size = LFS_CACHE_SIZE,
.lookahead = LFS_LOOKAHEAD,
}};
// Entry point
int main(void) {{
lfs2_emubd_create(&cfg, "blocks");
lfs_emubd_create(&cfg, "blocks");
{tests}
lfs2_emubd_destroy(&cfg);
lfs_emubd_destroy(&cfg);
}}

View File

@@ -28,7 +28,7 @@ def generate(test):
# Remove build artifacts to force rebuild
try:
os.remove('test.o')
os.remove('lfs2')
os.remove('lfs')
except OSError:
pass
@@ -39,9 +39,9 @@ def compile():
def execute():
if 'EXEC' in os.environ:
subprocess.check_call([os.environ['EXEC'], "./lfs2"])
subprocess.check_call([os.environ['EXEC'], "./lfs"])
else:
subprocess.check_call(["./lfs2"])
subprocess.check_call(["./lfs"])
def main(test=None):
if test and not test.startswith('-'):

View File

@@ -4,481 +4,479 @@ set -eu
echo "=== Allocator tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
SIZE=15000
lfs2_mkdir() {
lfs_mkdir() {
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "$1") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "$1") => 0;
lfs_unmount(&lfs) => 0;
TEST
}
lfs2_remove() {
lfs_remove() {
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_remove(&lfs2, "$1/eggs") => 0;
lfs2_remove(&lfs2, "$1/bacon") => 0;
lfs2_remove(&lfs2, "$1/pancakes") => 0;
lfs2_remove(&lfs2, "$1") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "$1/eggs") => 0;
lfs_remove(&lfs, "$1/bacon") => 0;
lfs_remove(&lfs, "$1/pancakes") => 0;
lfs_remove(&lfs, "$1") => 0;
lfs_unmount(&lfs) => 0;
TEST
}
lfs2_alloc_singleproc() {
lfs_alloc_singleproc() {
tests/test.py << TEST
const char *names[] = {"bacon", "eggs", "pancakes"};
lfs2_mount(&lfs2, &cfg) => 0;
for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs_mount(&lfs, &cfg) => 0;
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
sprintf((char*)buffer, "$1/%s", names[n]);
lfs2_file_open(&lfs2, &file[n], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
lfs_file_open(&lfs, &file[n], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
}
for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
size = strlen(names[n]);
for (int i = 0; i < $SIZE; i++) {
lfs2_file_write(&lfs2, &file[n], names[n], size) => size;
lfs_file_write(&lfs, &file[n], names[n], size) => size;
}
}
for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs2_file_close(&lfs2, &file[n]) => 0;
for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) {
lfs_file_close(&lfs, &file[n]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
}
lfs2_alloc_multiproc() {
lfs_alloc_multiproc() {
for name in bacon eggs pancakes
do
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "$1/$name",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "$1/$name",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("$name");
memcpy(buffer, "$name", size);
for (int i = 0; i < $SIZE; i++) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
done
}
lfs2_verify() {
lfs_verify() {
for name in bacon eggs pancakes
do
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "$1/$name", LFS2_O_RDONLY) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "$1/$name", LFS_O_RDONLY) => 0;
size = strlen("$name");
for (int i = 0; i < $SIZE; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "$name", size) => 0;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
done
}
echo "--- Single-process allocation test ---"
lfs2_mkdir singleproc
lfs2_alloc_singleproc singleproc
lfs2_verify singleproc
lfs_mkdir singleproc
lfs_alloc_singleproc singleproc
lfs_verify singleproc
echo "--- Multi-process allocation test ---"
lfs2_mkdir multiproc
lfs2_alloc_multiproc multiproc
lfs2_verify multiproc
lfs2_verify singleproc
lfs_mkdir multiproc
lfs_alloc_multiproc multiproc
lfs_verify multiproc
lfs_verify singleproc
echo "--- Single-process reuse test ---"
lfs2_remove singleproc
lfs2_mkdir singleprocreuse
lfs2_alloc_singleproc singleprocreuse
lfs2_verify singleprocreuse
lfs2_verify multiproc
lfs_remove singleproc
lfs_mkdir singleprocreuse
lfs_alloc_singleproc singleprocreuse
lfs_verify singleprocreuse
lfs_verify multiproc
echo "--- Multi-process reuse test ---"
lfs2_remove multiproc
lfs2_mkdir multiprocreuse
lfs2_alloc_singleproc multiprocreuse
lfs2_verify multiprocreuse
lfs2_verify singleprocreuse
lfs_remove multiproc
lfs_mkdir multiprocreuse
lfs_alloc_singleproc multiprocreuse
lfs_verify multiprocreuse
lfs_verify singleprocreuse
echo "--- Cleanup ---"
lfs2_remove multiprocreuse
lfs2_remove singleprocreuse
lfs_remove multiprocreuse
lfs_remove singleprocreuse
echo "--- Exhaustion test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size);
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
lfs2_ssize_t res;
lfs_ssize_t res;
while (true) {
res = lfs2_file_write(&lfs2, &file[0], buffer, size);
res = lfs_file_write(&lfs, &file[0], buffer, size);
if (res < 0) {
break;
}
res => size;
}
res => LFS2_ERR_NOSPC;
res => LFS_ERR_NOSPC;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_RDONLY);
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion");
lfs2_file_size(&lfs2, &file[0]) => size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_size(&lfs, &file[0]) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Exhaustion wraparound test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_remove(&lfs2, "exhaustion") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "exhaustion") => 0;
lfs2_file_open(&lfs2, &file[0], "padding", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "padding", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("buffering");
memcpy(buffer, "buffering", size);
for (int i = 0; i < $SIZE; i++) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_remove(&lfs2, "padding") => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "padding") => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("exhaustion");
memcpy(buffer, "exhaustion", size);
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
lfs2_ssize_t res;
lfs_ssize_t res;
while (true) {
res = lfs2_file_write(&lfs2, &file[0], buffer, size);
res = lfs_file_write(&lfs, &file[0], buffer, size);
if (res < 0) {
break;
}
res => size;
}
res => LFS2_ERR_NOSPC;
res => LFS_ERR_NOSPC;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_RDONLY);
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion");
lfs2_file_size(&lfs2, &file[0]) => size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_size(&lfs, &file[0]) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "exhaustion", size) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_remove(&lfs2, "exhaustion") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_remove(&lfs, "exhaustion") => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Dir exhaustion test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
// find out max file size
lfs2_mkdir(&lfs2, "exhaustiondir") => 0;
lfs_mkdir(&lfs, "exhaustiondir") => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0;
int err;
while (true) {
err = lfs2_file_write(&lfs2, &file[0], buffer, size);
err = lfs_file_write(&lfs, &file[0], buffer, size);
if (err < 0) {
break;
}
count += 1;
}
err => LFS2_ERR_NOSPC;
lfs2_file_close(&lfs2, &file[0]) => 0;
err => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_remove(&lfs2, "exhaustion") => 0;
lfs2_remove(&lfs2, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0;
// see if dir fits with max file size
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
for (int i = 0; i < count; i++) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_mkdir(&lfs2, "exhaustiondir") => 0;
lfs2_remove(&lfs2, "exhaustiondir") => 0;
lfs2_remove(&lfs2, "exhaustion") => 0;
lfs_mkdir(&lfs, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0;
lfs_remove(&lfs, "exhaustion") => 0;
// see if dir fits with > max file size
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
for (int i = 0; i < count+1; i++) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_mkdir(&lfs2, "exhaustiondir") => LFS2_ERR_NOSPC;
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
lfs2_remove(&lfs2, "exhaustion") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_remove(&lfs, "exhaustion") => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Chained dir exhaustion test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
// find out max file size
lfs2_mkdir(&lfs2, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) {
lfs_mkdir(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 9; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
lfs_mkdir(&lfs, (char*)buffer) => 0;
}
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0;
int err;
while (true) {
err = lfs2_file_write(&lfs2, &file[0], buffer, size);
err = lfs_file_write(&lfs, &file[0], buffer, size);
if (err < 0) {
break;
}
count += 1;
}
err => LFS2_ERR_NOSPC;
lfs2_file_close(&lfs2, &file[0]) => 0;
err => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_remove(&lfs2, "exhaustion") => 0;
lfs2_remove(&lfs2, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) {
lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 9; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs2_remove(&lfs2, (char*)buffer) => 0;
lfs_remove(&lfs, (char*)buffer) => 0;
}
// see that chained dir fails
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
for (int i = 0; i < count+1; i++) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
for (int i = 0; i < 10; i++) {
for (int i = 0; i < 9; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
lfs_mkdir(&lfs, (char*)buffer) => 0;
}
lfs2_mkdir(&lfs2, "exhaustiondir") => LFS2_ERR_NOSPC;
lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC;
// shorten file to try a second chained dir
while (true) {
err = lfs2_mkdir(&lfs2, "exhaustiondir");
if (err != LFS2_ERR_NOSPC) {
err = lfs_mkdir(&lfs, "exhaustiondir");
if (err != LFS_ERR_NOSPC) {
break;
}
lfs2_ssize_t filesize = lfs2_file_size(&lfs2, &file[0]);
lfs_ssize_t filesize = lfs_file_size(&lfs, &file[0]);
filesize > 0 => true;
lfs2_file_truncate(&lfs2, &file[0], filesize - size) => 0;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_truncate(&lfs, &file[0], filesize - size) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
}
err => 0;
lfs2_mkdir(&lfs2, "exhaustiondir2") => LFS2_ERR_NOSPC;
lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Split dir test ---"
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
// create one block hole for half a directory
lfs2_file_open(&lfs2, &file[0], "bump", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
for (lfs2_size_t i = 0; i < cfg.block_size; i += 2) {
lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs2_file_write(&lfs2, &file[0], buffer, cfg.block_size) => cfg.block_size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => cfg.block_size;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT);
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
// remount to force reset of lookahead
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
// open hole
lfs2_remove(&lfs2, "bump") => 0;
lfs_remove(&lfs, "bump") => 0;
lfs2_mkdir(&lfs2, "splitdir") => 0;
lfs2_file_open(&lfs2, &file[0], "splitdir/bump",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
for (lfs2_size_t i = 0; i < cfg.block_size; i += 2) {
lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file[0], "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs2_file_write(&lfs2, &file[0], buffer, 2*cfg.block_size) => LFS2_ERR_NOSPC;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Outdated lookahead test ---"
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
// fill completely with two files
lfs2_file_open(&lfs2, &file[0], "exhaustion1",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion2",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
// remount to force reset of lookahead
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0;
// rewrite one file
lfs2_file_open(&lfs2, &file[0], "exhaustion1",
LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
// rewrite second file, this requires lookahead does not
// use old population
lfs2_file_open(&lfs2, &file[0], "exhaustion2",
LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
TEST
echo "--- Outdated lookahead and split dir test ---"
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
// fill completely with two files
lfs2_file_open(&lfs2, &file[0], "exhaustion1",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "exhaustion2",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion2",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
// remount to force reset of lookahead
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0;
// rewrite one file with a hole of one block
lfs2_file_open(&lfs2, &file[0], "exhaustion1",
LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion1",
LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
for (lfs2_size_t i = 0;
for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8);
i += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
// try to allocate a directory, should fail!
lfs2_mkdir(&lfs2, "split") => LFS2_ERR_NOSPC;
lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC;
// file should not fail
lfs2_file_open(&lfs2, &file[0], "notasplit",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_write(&lfs2, &file[0], "hi", 2) => 2;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "notasplit",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], "hi", 2) => 2;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -4,282 +4,258 @@ set -eu
echo "=== Attr tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "hello") => 0;
lfs2_file_open(&lfs2, &file[0], "hello/hello",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_write(&lfs2, &file[0], "hello", strlen("hello"))
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");
lfs2_file_close(&lfs2, &file[0]);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Set/get attribute ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_setattr(&lfs2, "hello", 'A', "aaaa", 4) => 0;
lfs2_setattr(&lfs2, "hello", 'B', "bbbbbb", 6) => 0;
lfs2_setattr(&lfs2, "hello", 'C', "ccccc", 5) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
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;
lfs2_setattr(&lfs2, "hello", 'B', "", 0) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 0;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
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;
lfs2_removeattr(&lfs2, "hello", 'B') => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => LFS2_ERR_NOATTR;
lfs2_getattr(&lfs2, "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;
lfs2_setattr(&lfs2, "hello", 'B', "dddddd", 6) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
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;
lfs2_setattr(&lfs2, "hello", 'B', "eee", 3) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 3;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
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;
lfs2_setattr(&lfs2, "hello", 'A', buffer, LFS2_ATTR_MAX+1) => LFS2_ERR_NOSPC;
lfs2_setattr(&lfs2, "hello", 'B', "fffffffff", 9) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 9;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
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;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 9) => 9;
lfs2_getattr(&lfs2, "hello", 'C', buffer+13, 5) => 5;
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;
lfs2_file_open(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, sizeof(buffer)) => strlen("hello");
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;
lfs2_file_close(&lfs2, &file[0]);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Set/get root attribute ---"
echo "--- Set/get fs attribute ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_setattr(&lfs2, "/", 'A', "aaaa", 4) => 0;
lfs2_setattr(&lfs2, "/", 'B', "bbbbbb", 6) => 0;
lfs2_setattr(&lfs2, "/", 'C', "ccccc", 5) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_mount(&lfs, &cfg) => 0;
lfs_fs_setattr(&lfs, 'A', "aaaa", 4) => 0;
lfs_fs_setattr(&lfs, 'B', "bbbbbb", 6) => 0;
lfs_fs_setattr(&lfs, 'C', "ccccc", 5) => 0;
lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 6;
lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "/", 'B', "", 0) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 0;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_fs_setattr(&lfs, 'B', "", 0) => 0;
lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 0;
lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_removeattr(&lfs2, "/", 'B') => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => LFS2_ERR_NOATTR;
lfs2_getattr(&lfs2, "/", '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;
lfs2_setattr(&lfs2, "/", 'B', "dddddd", 6) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_fs_setattr(&lfs, 'B', "dddddd", 6) => 0;
lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 6;
lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "/", 'B', "eee", 3) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 3;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_fs_setattr(&lfs, 'B', "eee", 3) => 0;
lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 3;
lfs_fs_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;
lfs2_setattr(&lfs2, "/", 'A', buffer, LFS2_ATTR_MAX+1) => LFS2_ERR_NOSPC;
lfs2_setattr(&lfs2, "/", 'B', "fffffffff", 9) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 9;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs2_unmount(&lfs2) => 0;
lfs_fs_setattr(&lfs, 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
lfs_fs_setattr(&lfs, 'B', "fffffffff", 9) => 0;
lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 9;
lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 9) => 9;
lfs2_getattr(&lfs2, "/", 'C', buffer+13, 5) => 5;
lfs_mount(&lfs, &cfg) => 0;
lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4;
lfs_fs_getattr(&lfs, 'B', buffer+4, 9) => 9;
lfs_fs_getattr(&lfs, 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, sizeof(buffer)) => strlen("hello");
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;
lfs2_file_close(&lfs2, &file[0]);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Set/get file attribute ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
struct lfs2_attr attrs1[] = {
{'A', buffer, 4},
{'B', buffer+4, 6},
{'C', buffer+10, 5},
};
struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
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};
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
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);
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
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;
attrs1[1].size = 0;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file[0]) => 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);
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
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;
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
b1.size = 6;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "dddddd", 6);
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
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;
attrs1[1].size = 3;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
b1.size = 3;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "eee", 3);
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
memset(buffer, 0, 15);
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
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;
attrs1[0].size = LFS2_ATTR_MAX+1;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_WRONLY, &cfg1)
=> LFS2_ERR_NOSPC;
a1.size = LFS_ATTR_MAX+1;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1)
=> LFS_ERR_NOSPC;
struct lfs2_attr attrs2[] = {
{'A', buffer, 4},
{'B', buffer+4, 9},
{'C', buffer+13, 5},
};
struct lfs2_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDWR, &cfg2) => 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_RDWR, &cfg2) => 0;
memcpy(buffer+4, "fffffffff", 9);
lfs2_file_close(&lfs2, &file[0]) => 0;
attrs1[0].size = 4;
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
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;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
struct lfs2_attr attrs2[] = {
{'A', buffer, 4},
{'B', buffer+4, 9},
{'C', buffer+13, 5},
};
struct lfs2_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
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};
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY, &cfg2) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
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;
lfs2_file_open(&lfs2, &file[0], "hello/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, sizeof(buffer)) => strlen("hello");
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;
lfs2_file_close(&lfs2, &file[0]);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]);
lfs_unmount(&lfs) => 0;
TEST
echo "--- Deferred file attributes ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
struct lfs2_attr attrs1[] = {
{'B', "gggg", 4},
{'C', "", 0},
{'D', "hhhh", 4},
};
struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
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};
lfs2_file_opencfg(&lfs2, &file[0], "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
lfs2_getattr(&lfs2, "hello/hello", 'B', buffer, 9) => 9;
lfs2_getattr(&lfs2, "hello/hello", 'C', buffer+9, 9) => 5;
lfs2_getattr(&lfs2, "hello/hello", 'D', buffer+18, 9) => LFS2_ERR_NOATTR;
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;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs2_getattr(&lfs2, "hello/hello", 'B', buffer, 9) => 4;
lfs2_getattr(&lfs2, "hello/hello", 'C', buffer+9, 9) => 0;
lfs2_getattr(&lfs2, "hello/hello", 'D', buffer+18, 9) => 4;
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;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -6,71 +6,71 @@ echo "=== Corrupt tests ==="
NAMEMULT=64
FILEMULT=1
lfs2_mktree() {
lfs_mktree() {
tests/test.py ${1:-} << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) {
for (int j = 0; j < $NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[$NAMEMULT] = '\0';
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
lfs_mkdir(&lfs, (char*)buffer) => 0;
buffer[$NAMEMULT] = '/';
for (int j = 0; j < $NAMEMULT; j++) {
buffer[j+$NAMEMULT+1] = '0'+i;
}
buffer[2*$NAMEMULT+1] = '\0';
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = $NAMEMULT;
for (int j = 0; j < i*$FILEMULT; j++) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
}
lfs2_chktree() {
lfs_chktree() {
tests/test.py ${1:-} << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (int i = 1; i < 10; i++) {
for (int j = 0; j < $NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[$NAMEMULT] = '\0';
lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS2_TYPE_DIR;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
buffer[$NAMEMULT] = '/';
for (int j = 0; j < $NAMEMULT; j++) {
buffer[j+$NAMEMULT+1] = '0'+i;
}
buffer[2*$NAMEMULT+1] = '\0';
lfs2_file_open(&lfs2, &file[0], (char*)buffer, LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_RDONLY) => 0;
size = $NAMEMULT;
for (int j = 0; j < i*$FILEMULT; j++) {
lfs2_file_read(&lfs2, &file[0], rbuffer, size) => size;
lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
}
echo "--- Sanity check ---"
rm -rf blocks
lfs2_mktree
lfs2_chktree
lfs_mktree
lfs_chktree
BLOCKS="$(ls blocks | grep -vw '[01]')"
echo "--- Block corruption ---"
@@ -79,8 +79,8 @@ do
rm -rf blocks
mkdir blocks
ln -s /dev/zero blocks/$b
lfs2_mktree
lfs2_chktree
lfs_mktree
lfs_chktree
done
echo "--- Block persistance ---"
@@ -88,10 +88,10 @@ for b in $BLOCKS
do
rm -rf blocks
mkdir blocks
lfs2_mktree
chmod a-w blocks/$b || true
lfs2_mktree
lfs2_chktree
lfs_mktree
chmod a-w blocks/$b
lfs_mktree
lfs_chktree
done
echo "--- Big region corruption ---"
@@ -101,8 +101,8 @@ for i in {2..512}
do
ln -s /dev/zero blocks/$(printf '%x' $i)
done
lfs2_mktree
lfs2_chktree
lfs_mktree
lfs_chktree
echo "--- Alternating corruption ---"
rm -rf blocks
@@ -111,8 +111,8 @@ for i in {2..1024..2}
do
ln -s /dev/zero blocks/$(printf '%x' $i)
done
lfs2_mktree
lfs2_chktree
lfs_mktree
lfs_chktree
echo "--- Results ---"
tests/stats.py

View File

@@ -6,294 +6,294 @@ LARGESIZE=128
echo "=== Directory tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
echo "--- Root directory ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Directory creation ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "potato") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- File creation ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "burito", LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Directory iteration ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS2_TYPE_REG;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "potato") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Directory failures ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "potato") => LFS2_ERR_EXIST;
lfs2_dir_open(&lfs2, &dir[0], "tomato") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "burito") => LFS2_ERR_NOTDIR;
lfs2_file_open(&lfs2, &file[0], "tomato", LFS2_O_RDONLY) => LFS2_ERR_NOENT;
lfs2_file_open(&lfs2, &file[0], "potato", LFS2_O_RDONLY) => LFS2_ERR_ISDIR;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST;
lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERR_NOTDIR;
lfs_file_open(&lfs, &file[0], "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file[0], "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Nested directories ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "potato/baked") => 0;
lfs2_mkdir(&lfs2, "potato/sweet") => 0;
lfs2_mkdir(&lfs2, "potato/fried") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "potato/baked") => 0;
lfs_mkdir(&lfs, "potato/sweet") => 0;
lfs_mkdir(&lfs, "potato/fried") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "potato") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "potato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Multi-block directory ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "cactus") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "cactus") => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "cactus/test%03d", i);
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
sprintf((char*)buffer, "cactus/test%d", i);
lfs_mkdir(&lfs, (char*)buffer) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "cactus") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "cactus") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
info.type => LFS_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "test%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
info.type => LFS2_TYPE_DIR;
info.type => LFS_TYPE_DIR;
}
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Directory remove ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_remove(&lfs2, "potato") => LFS2_ERR_NOTEMPTY;
lfs2_remove(&lfs2, "potato/sweet") => 0;
lfs2_remove(&lfs2, "potato/baked") => 0;
lfs2_remove(&lfs2, "potato/fried") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY;
lfs_remove(&lfs, "potato/sweet") => 0;
lfs_remove(&lfs, "potato/baked") => 0;
lfs_remove(&lfs, "potato/fried") => 0;
lfs2_dir_open(&lfs2, &dir[0], "potato") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "potato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs2_remove(&lfs2, "potato") => 0;
lfs_remove(&lfs, "potato") => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS2_TYPE_REG;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS2_TYPE_REG;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Directory rename ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "coldpotato") => 0;
lfs2_mkdir(&lfs2, "coldpotato/baked") => 0;
lfs2_mkdir(&lfs2, "coldpotato/sweet") => 0;
lfs2_mkdir(&lfs2, "coldpotato/fried") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_mkdir(&lfs, "coldpotato/baked") => 0;
lfs_mkdir(&lfs, "coldpotato/sweet") => 0;
lfs_mkdir(&lfs, "coldpotato/fried") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "coldpotato", "hotpotato") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "coldpotato", "hotpotato") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "hotpotato") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "hotpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "warmpotato") => 0;
lfs2_mkdir(&lfs2, "warmpotato/mushy") => 0;
lfs2_rename(&lfs2, "hotpotato", "warmpotato") => LFS2_ERR_NOTEMPTY;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "warmpotato") => 0;
lfs_mkdir(&lfs, "warmpotato/mushy") => 0;
lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERR_NOTEMPTY;
lfs2_remove(&lfs2, "warmpotato/mushy") => 0;
lfs2_rename(&lfs2, "hotpotato", "warmpotato") => 0;
lfs_remove(&lfs, "warmpotato/mushy") => 0;
lfs_rename(&lfs, "hotpotato", "warmpotato") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "warmpotato") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "warmpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "coldpotato") => 0;
lfs2_rename(&lfs2, "warmpotato/baked", "coldpotato/baked") => 0;
lfs2_rename(&lfs2, "warmpotato/sweet", "coldpotato/sweet") => 0;
lfs2_rename(&lfs2, "warmpotato/fried", "coldpotato/fried") => 0;
lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOTEMPTY;
lfs2_remove(&lfs2, "warmpotato") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0;
lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0;
lfs_rename(&lfs, "warmpotato/fried", "coldpotato/fried") => 0;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY;
lfs_remove(&lfs, "warmpotato") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "coldpotato") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "baked") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "sweet") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "fried") => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Recursive remove ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOTEMPTY;
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY;
lfs2_dir_open(&lfs2, &dir[0], "coldpotato") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
while (true) {
int err = lfs2_dir_read(&lfs2, &dir[0], &info);
int err = lfs_dir_read(&lfs, &dir[0], &info);
err >= 0 => 1;
if (err == 0) {
break;
@@ -301,183 +301,124 @@ tests/test.py << TEST
strcpy((char*)buffer, "coldpotato/");
strcat((char*)buffer, info.name);
lfs2_remove(&lfs2, (char*)buffer) => 0;
lfs_remove(&lfs, (char*)buffer) => 0;
}
lfs2_remove(&lfs2, "coldpotato") => 0;
lfs_remove(&lfs, "coldpotato") => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS2_TYPE_REG;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "cactus") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
TEST
echo "--- Multi-block rename ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "cactus/test%03d", i);
sprintf((char*)wbuffer, "cactus/tedd%03d", i);
lfs2_rename(&lfs2, (char*)buffer, (char*)wbuffer) => 0;
}
lfs2_unmount(&lfs2) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "cactus") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "tedd%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
info.type => LFS2_TYPE_DIR;
}
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Multi-block remove ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_remove(&lfs2, "cactus") => LFS2_ERR_NOTEMPTY;
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "cactus/tedd%03d", i);
lfs2_remove(&lfs2, (char*)buffer) => 0;
sprintf((char*)buffer, "cactus/test%d", i);
lfs_remove(&lfs, (char*)buffer) => 0;
}
lfs2_remove(&lfs2, "cactus") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_remove(&lfs, "cactus") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS2_TYPE_REG;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Multi-block directory with files ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "prickly-pear") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "prickly-pear") => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "prickly-pear/test%03d", i);
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
sprintf((char*)buffer, "prickly-pear/test%d", i);
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = 6;
memcpy(wbuffer, "Hello", size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "prickly-pear") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
info.type => LFS_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "test%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 6;
}
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
TEST
echo "--- Multi-block rename with files ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "prickly-pear/test%03d", i);
sprintf((char*)wbuffer, "prickly-pear/tedd%03d", i);
lfs2_rename(&lfs2, (char*)buffer, (char*)wbuffer) => 0;
}
lfs2_unmount(&lfs2) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "prickly-pear") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "tedd%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
info.type => LFS2_TYPE_REG;
info.size => 6;
}
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Multi-block remove with files ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_remove(&lfs2, "prickly-pear") => LFS2_ERR_NOTEMPTY;
lfs_mount(&lfs, &cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "prickly-pear/tedd%03d", i);
lfs2_remove(&lfs2, (char*)buffer) => 0;
sprintf((char*)buffer, "prickly-pear/test%d", i);
lfs_remove(&lfs, (char*)buffer) => 0;
}
lfs2_remove(&lfs2, "prickly-pear") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_remove(&lfs, "prickly-pear") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "burito") => 0;
info.type => LFS2_TYPE_REG;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -10,10 +10,10 @@ function read_file {
cat << TEST
size = $2;
lfs2_file_open(&lfs2, &file[0], "$1", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], rbuffer, size) => size;
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;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
TEST
}
@@ -21,19 +21,19 @@ function write_file {
cat << TEST
size = $2;
lfs2_file_open(&lfs2, &file[0], "$1",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[0], "$1",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
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
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 20)
$(write_file "hi1" 20)
$(write_file "hi2" 20)
@@ -46,14 +46,14 @@ tests/test.py << TEST
$(read_file "hi1" 200)
$(read_file "hi2" 20)
$(read_file "hi3" 20)
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry shrink test ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 20)
$(write_file "hi1" 200)
$(write_file "hi2" 20)
@@ -66,14 +66,14 @@ tests/test.py << TEST
$(read_file "hi1" 20)
$(read_file "hi2" 20)
$(read_file "hi3" 20)
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry spill test ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 200)
$(write_file "hi2" 200)
@@ -83,14 +83,14 @@ tests/test.py << TEST
$(read_file "hi1" 200)
$(read_file "hi2" 200)
$(read_file "hi3" 200)
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry push spill test ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 20)
$(write_file "hi2" 200)
@@ -103,14 +103,14 @@ tests/test.py << TEST
$(read_file "hi1" 200)
$(read_file "hi2" 200)
$(read_file "hi3" 200)
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry push spill two test ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 20)
$(write_file "hi2" 200)
@@ -125,96 +125,96 @@ tests/test.py << TEST
$(read_file "hi2" 200)
$(read_file "hi3" 200)
$(read_file "hi4" 200)
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Entry drop test ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
$(write_file "hi0" 200)
$(write_file "hi1" 200)
$(write_file "hi2" 200)
$(write_file "hi3" 200)
lfs2_remove(&lfs2, "hi1") => 0;
lfs2_stat(&lfs2, "hi1", &info) => LFS2_ERR_NOENT;
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)
lfs2_remove(&lfs2, "hi2") => 0;
lfs2_stat(&lfs2, "hi2", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "hi2") => 0;
lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT;
$(read_file "hi0" 200)
$(read_file "hi3" 200)
lfs2_remove(&lfs2, "hi3") => 0;
lfs2_stat(&lfs2, "hi3", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "hi3") => 0;
lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT;
$(read_file "hi0" 200)
lfs2_remove(&lfs2, "hi0") => 0;
lfs2_stat(&lfs2, "hi0", &info) => LFS2_ERR_NOENT;
lfs2_unmount(&lfs2) => 0;
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
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 'm', 200);
buffer[200] = '\0';
size = 400;
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
size = 400;
lfs2_file_open(&lfs2, &file[0], (char*)buffer, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], rbuffer, size) => size;
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;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Resize too big ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
memset(buffer, 'm', 200);
buffer[200] = '\0';
size = 40;
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
size = 40;
lfs2_file_open(&lfs2, &file[0], (char*)buffer, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], rbuffer, size) => size;
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;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
size = 400;
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
size = 400;
lfs2_file_open(&lfs2, &file[0], (char*)buffer, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], rbuffer, size) => size;
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;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -8,65 +8,65 @@ LARGESIZE=262144
echo "=== File tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
echo "--- Simple file test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("Hello World!\n");
memcpy(wbuffer, "Hello World!\n", size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "hello", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[0], "hello", LFS_O_RDONLY) => 0;
size = strlen("Hello World!\n");
lfs2_file_read(&lfs2, &file[0], rbuffer, size) => size;
lfs_file_read(&lfs, &file[0], rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
w_test() {
tests/test.py ${4:-} << TEST
tests/test.py << TEST
size = $1;
lfs2_size_t chunk = 31;
lfs_size_t chunk = 31;
srand(0);
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "$2",
${3:-LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC}) => 0;
for (lfs2_size_t i = 0; i < size; i += chunk) {
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "$2",
${3:-LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC}) => 0;
for (lfs_size_t i = 0; i < size; i += chunk) {
chunk = (chunk < size - i) ? chunk : size - i;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = rand() & 0xff;
}
lfs2_file_write(&lfs2, &file[0], buffer, chunk) => chunk;
lfs_file_write(&lfs, &file[0], buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
}
r_test() {
tests/test.py << TEST
size = $1;
lfs2_size_t chunk = 29;
lfs_size_t chunk = 29;
srand(0);
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "$2", &info) => 0;
info.type => LFS2_TYPE_REG;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "$2", &info) => 0;
info.type => LFS_TYPE_REG;
info.size => size;
lfs2_file_open(&lfs2, &file[0], "$2", ${3:-LFS2_O_RDONLY}) => 0;
for (lfs2_size_t i = 0; i < size; i += chunk) {
lfs_file_open(&lfs, &file[0], "$2", ${3:-LFS_O_RDONLY}) => 0;
for (lfs_size_t i = 0; i < size; i += chunk) {
chunk = (chunk < size - i) ? chunk : size - i;
lfs2_file_read(&lfs2, &file[0], buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk && i+b < size; b++) {
lfs_file_read(&lfs, &file[0], buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk && i+b < size; b++) {
buffer[b] => rand() & 0xff;
}
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
}
@@ -106,52 +106,52 @@ r_test 0 noavacado
echo "--- Dir check ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => strlen("Hello World!\n");
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "largeavacado") => 0;
info.type => LFS2_TYPE_REG;
info.size => $LARGESIZE;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "mediumavacado") => 0;
info.type => LFS2_TYPE_REG;
info.size => $MEDIUMSIZE;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "noavacado") => 0;
info.type => LFS2_TYPE_REG;
info.size => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "smallavacado") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => $SMALLSIZE;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "mediumavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => $MEDIUMSIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "largeavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => $LARGESIZE;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "noavacado") => 0;
info.type => LFS_TYPE_REG;
info.size => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Many file test ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
tests/test.py << TEST
// Create 300 files of 6 bytes
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "directory") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "directory") => 0;
for (unsigned i = 0; i < 300; i++) {
snprintf((char*)buffer, sizeof(buffer), "file_%03d", i);
lfs2_file_open(&lfs2, &file[0], (char*)buffer, LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = 6;
memcpy(wbuffer, "Hello", size);
lfs2_file_write(&lfs2, &file[0], wbuffer, size) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_write(&lfs, &file[0], wbuffer, size) => size;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -6,44 +6,45 @@ rm -rf blocks
echo "--- Basic formatting ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
echo "--- Basic mounting ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Invalid superblocks ---"
ln -f -s /dev/zero blocks/0
ln -f -s /dev/zero blocks/1
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => LFS2_ERR_NOSPC;
lfs_format(&lfs, &cfg) => LFS_ERR_CORRUPT;
TEST
rm blocks/0 blocks/1
echo "--- Invalid mount ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT;
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
TEST
echo "--- Expanding superblock ---"
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (int i = 0; i < 100; i++) {
lfs2_mkdir(&lfs2, "dummy") => 0;
lfs2_remove(&lfs2, "dummy") => 0;
lfs_mkdir(&lfs, "dummy") => 0;
lfs_remove(&lfs, "dummy") => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "dummy") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "dummy") => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -4,182 +4,182 @@ set -eu
echo "=== Interspersed tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
echo "--- Interspersed file test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "a", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_open(&lfs2, &file[1], "b", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_open(&lfs2, &file[2], "c", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_open(&lfs2, &file[3], "d", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &file[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &file[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &file[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < 10; i++) {
lfs2_file_write(&lfs2, &file[0], (const void*)"a", 1) => 1;
lfs2_file_write(&lfs2, &file[1], (const void*)"b", 1) => 1;
lfs2_file_write(&lfs2, &file[2], (const void*)"c", 1) => 1;
lfs2_file_write(&lfs2, &file[3], (const void*)"d", 1) => 1;
lfs_file_write(&lfs, &file[0], (const void*)"a", 1) => 1;
lfs_file_write(&lfs, &file[1], (const void*)"b", 1) => 1;
lfs_file_write(&lfs, &file[2], (const void*)"c", 1) => 1;
lfs_file_write(&lfs, &file[3], (const void*)"d", 1) => 1;
}
lfs2_file_close(&lfs2, &file[0]);
lfs2_file_close(&lfs2, &file[1]);
lfs2_file_close(&lfs2, &file[2]);
lfs2_file_close(&lfs2, &file[3]);
lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &file[1]);
lfs_file_close(&lfs, &file[2]);
lfs_file_close(&lfs, &file[3]);
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "a") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "b") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "c") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "d") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "a", LFS2_O_RDONLY) => 0;
lfs2_file_open(&lfs2, &file[1], "b", LFS2_O_RDONLY) => 0;
lfs2_file_open(&lfs2, &file[2], "c", LFS2_O_RDONLY) => 0;
lfs2_file_open(&lfs2, &file[3], "d", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[0], "a", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[1], "b", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[2], "c", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[3], "d", LFS_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, 1) => 1;
lfs_file_read(&lfs, &file[0], buffer, 1) => 1;
buffer[0] => 'a';
lfs2_file_read(&lfs2, &file[1], buffer, 1) => 1;
lfs_file_read(&lfs, &file[1], buffer, 1) => 1;
buffer[0] => 'b';
lfs2_file_read(&lfs2, &file[2], buffer, 1) => 1;
lfs_file_read(&lfs, &file[2], buffer, 1) => 1;
buffer[0] => 'c';
lfs2_file_read(&lfs2, &file[3], buffer, 1) => 1;
lfs_file_read(&lfs, &file[3], buffer, 1) => 1;
buffer[0] => 'd';
}
lfs2_file_close(&lfs2, &file[0]);
lfs2_file_close(&lfs2, &file[1]);
lfs2_file_close(&lfs2, &file[2]);
lfs2_file_close(&lfs2, &file[3]);
lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &file[1]);
lfs_file_close(&lfs, &file[2]);
lfs_file_close(&lfs, &file[3]);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Interspersed remove file test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "e", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
}
lfs2_remove(&lfs2, "a") => 0;
lfs2_remove(&lfs2, "b") => 0;
lfs2_remove(&lfs2, "c") => 0;
lfs2_remove(&lfs2, "d") => 0;
lfs_remove(&lfs, "a") => 0;
lfs_remove(&lfs, "b") => 0;
lfs_remove(&lfs, "c") => 0;
lfs_remove(&lfs, "d") => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
}
lfs2_file_close(&lfs2, &file[0]);
lfs_file_close(&lfs, &file[0]);
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "e") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "e", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, 1) => 1;
lfs_file_read(&lfs, &file[0], buffer, 1) => 1;
buffer[0] => 'e';
}
lfs2_file_close(&lfs2, &file[0]);
lfs_file_close(&lfs, &file[0]);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Remove inconveniently test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "e", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs2_file_open(&lfs2, &file[1], "f", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_open(&lfs2, &file[2], "g", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &file[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file[0], (const void*)"e", 1) => 1;
lfs2_file_write(&lfs2, &file[1], (const void*)"f", 1) => 1;
lfs2_file_write(&lfs2, &file[2], (const void*)"g", 1) => 1;
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1;
}
lfs2_remove(&lfs2, "f") => 0;
lfs_remove(&lfs, "f") => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file[0], (const void*)"e", 1) => 1;
lfs2_file_write(&lfs2, &file[1], (const void*)"f", 1) => 1;
lfs2_file_write(&lfs2, &file[2], (const void*)"g", 1) => 1;
lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1;
}
lfs2_file_close(&lfs2, &file[0]);
lfs2_file_close(&lfs2, &file[1]);
lfs2_file_close(&lfs2, &file[2]);
lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &file[1]);
lfs_file_close(&lfs, &file[2]);
lfs2_dir_open(&lfs2, &dir[0], "/") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "/") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
info.type => LFS2_TYPE_DIR;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "e") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "g") => 0;
info.type => LFS2_TYPE_REG;
info.type => LFS_TYPE_REG;
info.size => 10;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs2_file_open(&lfs2, &file[0], "e", LFS2_O_RDONLY) => 0;
lfs2_file_open(&lfs2, &file[1], "g", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &file[1], "g", LFS_O_RDONLY) => 0;
for (int i = 0; i < 10; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, 1) => 1;
lfs_file_read(&lfs, &file[0], buffer, 1) => 1;
buffer[0] => 'e';
lfs2_file_read(&lfs2, &file[1], buffer, 1) => 1;
lfs_file_read(&lfs, &file[1], buffer, 1) => 1;
buffer[0] => 'g';
}
lfs2_file_close(&lfs2, &file[0]);
lfs2_file_close(&lfs2, &file[1]);
lfs_file_close(&lfs, &file[0]);
lfs_file_close(&lfs, &file[1]);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -4,327 +4,327 @@ set -eu
echo "=== Move tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "a") => 0;
lfs2_mkdir(&lfs2, "b") => 0;
lfs2_mkdir(&lfs2, "c") => 0;
lfs2_mkdir(&lfs2, "d") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "d") => 0;
lfs2_mkdir(&lfs2, "a/hi") => 0;
lfs2_mkdir(&lfs2, "a/hi/hola") => 0;
lfs2_mkdir(&lfs2, "a/hi/bonjour") => 0;
lfs2_mkdir(&lfs2, "a/hi/ohayo") => 0;
lfs_mkdir(&lfs, "a/hi") => 0;
lfs_mkdir(&lfs, "a/hi/hola") => 0;
lfs_mkdir(&lfs, "a/hi/bonjour") => 0;
lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs2_file_open(&lfs2, &file[0], "a/hello", LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file[0], "hola\n", 5) => 5;
lfs2_file_write(&lfs2, &file[0], "bonjour\n", 8) => 8;
lfs2_file_write(&lfs2, &file[0], "ohayo\n", 6) => 6;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_open(&lfs, &file[0], "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file[0], "hola\n", 5) => 5;
lfs_file_write(&lfs, &file[0], "bonjour\n", 8) => 8;
lfs_file_write(&lfs, &file[0], "ohayo\n", 6) => 6;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move file ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "a/hello", "b/hello") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hello", "b/hello") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "a") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "a") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "b") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move file corrupt source ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "b/hello", "c/hello") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/corrupt.py -n 1
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "b") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "c") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move file corrupt source and dest ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "c/hello", "d/hello") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/corrupt.py -n 2
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "c") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "d") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move file after corrupt ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "c/hello", "d/hello") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "c") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "d") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move dir ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "a/hi", "b/hi") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "a/hi", "b/hi") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "a") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "a") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "b") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move dir corrupt source ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "b/hi", "c/hi") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "b/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/corrupt.py -n 1
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "b") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "c") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move dir corrupt source and dest ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "c/hi", "d/hi") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hi", "d/hi") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/corrupt.py -n 2
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "c") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "d") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move dir after corrupt ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_rename(&lfs2, "c/hi", "d/hi") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_rename(&lfs, "c/hi", "d/hi") => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "c") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "d") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
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;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move check ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "a/hi") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "b/hi") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "c/hi") => LFS2_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "b/hi") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "c/hi") => LFS_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "d/hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "d/hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hola") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "ohayo") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "a/hello") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "b/hello") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "c/hello") => LFS2_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "b/hello") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir[0], "c/hello") => LFS_ERR_NOENT;
lfs2_file_open(&lfs2, &file[0], "d/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, 5) => 5;
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;
lfs2_file_read(&lfs2, &file[0], buffer, 8) => 8;
lfs_file_read(&lfs, &file[0], buffer, 8) => 8;
memcmp(buffer, "bonjour\n", 8) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, 6) => 6;
lfs_file_read(&lfs, &file[0], buffer, 6) => 6;
memcmp(buffer, "ohayo\n", 6) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Move state stealing ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs2_remove(&lfs2, "b") => 0;
lfs2_remove(&lfs2, "c") => 0;
lfs_remove(&lfs, "b") => 0;
lfs_remove(&lfs, "c") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "a/hi") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "b") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "c") => LFS2_ERR_NOENT;
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;
lfs2_dir_open(&lfs2, &dir[0], "d/hi") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_open(&lfs, &dir[0], "d/hi") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "hola") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "bonjour") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "ohayo") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs2_dir_open(&lfs2, &dir[0], "a/hello") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "b") => LFS2_ERR_NOENT;
lfs2_dir_open(&lfs2, &dir[0], "c") => LFS2_ERR_NOENT;
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;
lfs2_file_open(&lfs2, &file[0], "d/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, 5) => 5;
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;
lfs2_file_read(&lfs2, &file[0], buffer, 8) => 8;
lfs_file_read(&lfs, &file[0], buffer, 8) => 8;
memcmp(buffer, "bonjour\n", 8) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, 6) => 6;
lfs_file_read(&lfs, &file[0], buffer, 6) => 6;
memcmp(buffer, "ohayo\n", 6) => 0;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST

View File

@@ -4,41 +4,41 @@ set -eu
echo "=== Orphan tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
echo "--- Orphan test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "parent") => 0;
lfs2_mkdir(&lfs2, "parent/orphan") => 0;
lfs2_mkdir(&lfs2, "parent/child") => 0;
lfs2_remove(&lfs2, "parent/orphan") => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0;
lfs_remove(&lfs, "parent/orphan") => 0;
TEST
# corrupt most recent commit, this should be the update to the previous
# linked-list entry and should orphan the child
tests/corrupt.py
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_ssize_t before = lfs2_fs_size(&lfs2);
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_ssize_t before = lfs_fs_size(&lfs);
before => 8;
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_ssize_t orphaned = lfs2_fs_size(&lfs2);
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_ssize_t orphaned = lfs_fs_size(&lfs);
orphaned => 8;
lfs2_mkdir(&lfs2, "parent/otherchild") => 0;
lfs_mkdir(&lfs, "parent/otherchild") => 0;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_ssize_t deorphaned = lfs2_fs_size(&lfs2);
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_ssize_t deorphaned = lfs_fs_size(&lfs);
deorphaned => 8;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -4,165 +4,157 @@ set -eu
echo "=== Path tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "tea") => 0;
lfs2_mkdir(&lfs2, "coffee") => 0;
lfs2_mkdir(&lfs2, "soda") => 0;
lfs2_mkdir(&lfs2, "tea/hottea") => 0;
lfs2_mkdir(&lfs2, "tea/warmtea") => 0;
lfs2_mkdir(&lfs2, "tea/coldtea") => 0;
lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0;
lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0;
lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0;
lfs2_mkdir(&lfs2, "soda/hotsoda") => 0;
lfs2_mkdir(&lfs2, "soda/warmsoda") => 0;
lfs2_mkdir(&lfs2, "soda/coldsoda") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "soda") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
lfs_mkdir(&lfs, "soda/hotsoda") => 0;
lfs_mkdir(&lfs, "soda/warmsoda") => 0;
lfs_mkdir(&lfs, "soda/coldsoda") => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Root path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "tea/hottea", &info) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "/tea/hottea", &info) => 0;
lfs_stat(&lfs, "/tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_mkdir(&lfs2, "/milk1") => 0;
lfs2_stat(&lfs2, "/milk1", &info) => 0;
lfs_mkdir(&lfs, "/milk1") => 0;
lfs_stat(&lfs, "/milk1", &info) => 0;
strcmp(info.name, "milk1") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Redundant slash path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "/tea/hottea", &info) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "/tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "//tea//hottea", &info) => 0;
lfs_stat(&lfs, "//tea//hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "///tea///hottea", &info) => 0;
lfs_stat(&lfs, "///tea///hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_mkdir(&lfs2, "///milk2") => 0;
lfs2_stat(&lfs2, "///milk2", &info) => 0;
lfs_mkdir(&lfs, "///milk2") => 0;
lfs_stat(&lfs, "///milk2", &info) => 0;
strcmp(info.name, "milk2") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Dot path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "./tea/hottea", &info) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "./tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "/./tea/hottea", &info) => 0;
lfs_stat(&lfs, "/./tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "/././tea/hottea", &info) => 0;
lfs_stat(&lfs, "/././tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "/./tea/./hottea", &info) => 0;
lfs_stat(&lfs, "/./tea/./hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_mkdir(&lfs2, "/./milk3") => 0;
lfs2_stat(&lfs2, "/./milk3", &info) => 0;
lfs_mkdir(&lfs, "/./milk3") => 0;
lfs_stat(&lfs, "/./milk3", &info) => 0;
strcmp(info.name, "milk3") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Dot dot path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "coffee/../tea/hottea", &info) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "tea/coldtea/../hottea", &info) => 0;
lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "coffee/coldcoffee/../../tea/hottea", &info) => 0;
lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "coffee/../soda/../tea/hottea", &info) => 0;
lfs_stat(&lfs, "coffee/../soda/../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_mkdir(&lfs2, "coffee/../milk4") => 0;
lfs2_stat(&lfs2, "coffee/../milk4", &info) => 0;
lfs_mkdir(&lfs, "coffee/../milk4") => 0;
lfs_stat(&lfs, "coffee/../milk4", &info) => 0;
strcmp(info.name, "milk4") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Trailing dot path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "tea/hottea/", &info) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "tea/hottea/", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "tea/hottea/.", &info) => 0;
lfs_stat(&lfs, "tea/hottea/.", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "tea/hottea/./.", &info) => 0;
lfs_stat(&lfs, "tea/hottea/./.", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_stat(&lfs2, "tea/hottea/..", &info) => 0;
lfs_stat(&lfs, "tea/hottea/..", &info) => 0;
strcmp(info.name, "tea") => 0;
lfs2_stat(&lfs2, "tea/hottea/../.", &info) => 0;
lfs_stat(&lfs, "tea/hottea/../.", &info) => 0;
strcmp(info.name, "tea") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Root dot dot path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "coffee/../../../../../../tea/hottea", &info) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
lfs2_mkdir(&lfs2, "coffee/../../../../../../milk5") => 0;
lfs2_stat(&lfs2, "coffee/../../../../../../milk5", &info) => 0;
lfs_mkdir(&lfs, "coffee/../../../../../../milk5") => 0;
lfs_stat(&lfs, "coffee/../../../../../../milk5", &info) => 0;
strcmp(info.name, "milk5") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Root tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_stat(&lfs2, "/", &info) => 0;
info.type => LFS2_TYPE_DIR;
lfs_mount(&lfs, &cfg) => 0;
lfs_stat(&lfs, "/", &info) => 0;
info.type => LFS_TYPE_DIR;
strcmp(info.name, "/") => 0;
lfs2_mkdir(&lfs2, "/") => LFS2_ERR_EXIST;
lfs2_file_open(&lfs2, &file[0], "/", LFS2_O_WRONLY | LFS2_O_CREAT)
=> LFS2_ERR_ISDIR;
lfs2_unmount(&lfs2) => 0;
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
lfs_file_open(&lfs, &file[0], "/", LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_ISDIR;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Sketchy path tests ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "dirt/ground") => LFS2_ERR_NOENT;
lfs2_mkdir(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT;
lfs2_unmount(&lfs2) => 0;
TEST
echo "--- Superblock conflict test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "littlefs") => 0;
lfs2_remove(&lfs2, "littlefs") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Max path test ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
memset(buffer, 'w', LFS2_NAME_MAX+1);
buffer[LFS2_NAME_MAX+2] = '\0';
lfs2_mkdir(&lfs2, (char*)buffer) => LFS2_ERR_NAMETOOLONG;
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_NAMETOOLONG;
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', LFS2_NAME_MAX+1);
buffer[strlen("coffee/")+LFS2_NAME_MAX+2] = '\0';
lfs2_mkdir(&lfs2, (char*)buffer) => LFS2_ERR_NAMETOOLONG;
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_NAMETOOLONG;
lfs2_unmount(&lfs2) => 0;
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
echo "--- Results ---"

View File

@@ -8,353 +8,353 @@ LARGESIZE=132
echo "=== Seek tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_mkdir(&lfs2, "hello") => 0;
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "hello/kitty%03d", i);
lfs2_file_open(&lfs2, &file[0], (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
sprintf((char*)buffer, "hello/kitty%d", i);
lfs_file_open(&lfs, &file[0], (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat");
memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < $LARGESIZE; j++) {
lfs2_file_write(&lfs2, &file[0], buffer, size);
lfs_file_write(&lfs, &file[0], buffer, size);
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Simple dir seek ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_soff_t pos;
lfs_soff_t pos;
int i;
for (i = 0; i < $SMALLSIZE; i++) {
sprintf((char*)buffer, "kitty%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
pos = lfs2_dir_tell(&lfs2, &dir[0]);
pos = lfs_dir_tell(&lfs, &dir[0]);
}
pos >= 0 => 1;
lfs2_dir_seek(&lfs2, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
lfs2_dir_rewind(&lfs2, &dir[0]) => 0;
sprintf((char*)buffer, "kitty%03d", 0);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_rewind(&lfs, &dir[0]) => 0;
sprintf((char*)buffer, "kitty%d", 0);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
lfs2_dir_seek(&lfs2, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Large dir seek ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_dir_open(&lfs2, &dir[0], "hello") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "hello") => 0;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_soff_t pos;
lfs_soff_t pos;
int i;
for (i = 0; i < $MEDIUMSIZE; i++) {
sprintf((char*)buffer, "kitty%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
pos = lfs2_dir_tell(&lfs2, &dir[0]);
pos = lfs_dir_tell(&lfs, &dir[0]);
}
pos >= 0 => 1;
lfs2_dir_seek(&lfs2, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
lfs2_dir_rewind(&lfs2, &dir[0]) => 0;
sprintf((char*)buffer, "kitty%03d", 0);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_rewind(&lfs, &dir[0]) => 0;
sprintf((char*)buffer, "kitty%d", 0);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, ".") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, "..") => 0;
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
lfs2_dir_seek(&lfs2, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%03d", i);
lfs2_dir_read(&lfs2, &dir[0], &info) => 1;
lfs_dir_seek(&lfs, &dir[0], pos) => 0;
sprintf((char*)buffer, "kitty%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1;
strcmp(info.name, (char*)buffer) => 0;
lfs2_dir_close(&lfs2, &dir[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_close(&lfs, &dir[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Simple file seek ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/kitty042", LFS2_O_RDONLY) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0;
lfs2_soff_t pos;
lfs_soff_t pos;
size = strlen("kittycatcat");
for (int i = 0; i < $SMALLSIZE; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs2_file_tell(&lfs2, &file[0]);
pos = lfs_file_tell(&lfs, &file[0]);
}
pos >= 0 => 1;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_rewind(&lfs2, &file[0]) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_CUR) => size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], size, LFS2_SEEK_CUR) => 3*size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -size, LFS2_SEEK_CUR) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -size, LFS2_SEEK_END) >= 0 => 1;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
size = lfs2_file_size(&lfs2, &file[0]);
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_CUR) => size;
size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Large file seek ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/kitty042", LFS2_O_RDONLY) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0;
lfs2_soff_t pos;
lfs_soff_t pos;
size = strlen("kittycatcat");
for (int i = 0; i < $MEDIUMSIZE; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs2_file_tell(&lfs2, &file[0]);
pos = lfs_file_tell(&lfs, &file[0]);
}
pos >= 0 => 1;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_rewind(&lfs2, &file[0]) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_CUR) => size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], size, LFS2_SEEK_CUR) => 3*size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -size, LFS2_SEEK_CUR) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -size, LFS2_SEEK_END) >= 0 => 1;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
size = lfs2_file_size(&lfs2, &file[0]);
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_CUR) => size;
size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Simple file seek and write ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/kitty042", LFS2_O_RDWR) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
lfs2_soff_t pos;
lfs_soff_t pos;
size = strlen("kittycatcat");
for (int i = 0; i < $SMALLSIZE; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs2_file_tell(&lfs2, &file[0]);
pos = lfs_file_tell(&lfs, &file[0]);
}
pos >= 0 => 1;
memcpy(buffer, "doggodogdog", size);
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0;
lfs2_file_rewind(&lfs2, &file[0]) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -size, LFS2_SEEK_END) >= 0 => 1;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
size = lfs2_file_size(&lfs2, &file[0]);
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_CUR) => size;
size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Large file seek and write ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/kitty042", LFS2_O_RDWR) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
lfs2_soff_t pos;
lfs_soff_t pos;
size = strlen("kittycatcat");
for (int i = 0; i < $MEDIUMSIZE; i++) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
if (i != $SMALLSIZE) {
memcmp(buffer, "kittycatcat", size) => 0;
}
pos = lfs2_file_tell(&lfs2, &file[0]);
pos = lfs_file_tell(&lfs, &file[0]);
}
pos >= 0 => 1;
memcpy(buffer, "doggodogdog", size);
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0;
lfs2_file_rewind(&lfs2, &file[0]) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_rewind(&lfs, &file[0]) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file[0], pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -size, LFS2_SEEK_END) >= 0 => 1;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
size = lfs2_file_size(&lfs2, &file[0]);
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_CUR) => size;
size = lfs_file_size(&lfs, &file[0]);
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Boundary seek and write ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/kitty042", LFS2_O_RDWR) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
size = strlen("hedgehoghog");
const lfs2_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs2_soff_t off = offsets[i];
for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs_soff_t off = offsets[i];
memcpy(buffer, "hedgehoghog", size);
lfs2_file_seek(&lfs2, &file[0], off, LFS2_SEEK_SET) => off;
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs2_file_seek(&lfs2, &file[0], off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0;
lfs2_file_seek(&lfs2, &file[0], 0, LFS2_SEEK_SET) => 0;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_SET) => 0;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_sync(&lfs2, &file[0]) => 0;
lfs_file_sync(&lfs, &file[0]) => 0;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Out-of-bounds seek ---"
tests/test.py << TEST
lfs2_mount(&lfs2, &cfg) => 0;
lfs2_file_open(&lfs2, &file[0], "hello/kitty042", LFS2_O_RDWR) => 0;
lfs_mount(&lfs, &cfg) => 0;
lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0;
size = strlen("kittycatcat");
lfs2_file_size(&lfs2, &file[0]) => $LARGESIZE*size;
lfs2_file_seek(&lfs2, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS2_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => 0;
lfs_file_size(&lfs, &file[0]) => $LARGESIZE*size;
lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs_file_read(&lfs, &file[0], buffer, size) => 0;
memcpy(buffer, "porcupineee", size);
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
lfs_file_write(&lfs, &file[0], buffer, size) => size;
lfs2_file_seek(&lfs2, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS2_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size,
LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "porcupineee", size) => 0;
lfs2_file_seek(&lfs2, &file[0], $LARGESIZE*size,
LFS2_SEEK_SET) => $LARGESIZE*size;
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_seek(&lfs, &file[0], $LARGESIZE*size,
LFS_SEEK_SET) => $LARGESIZE*size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0;
lfs2_file_seek(&lfs2, &file[0], -(($LARGESIZE+$SMALLSIZE)*size),
LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
lfs2_file_tell(&lfs2, &file[0]) => ($LARGESIZE+1)*size;
lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+$SMALLSIZE)*size),
LFS_SEEK_CUR) => LFS_ERR_INVAL;
lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size;
lfs2_file_seek(&lfs2, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size),
LFS2_SEEK_END) => LFS2_ERR_INVAL;
lfs2_file_tell(&lfs2, &file[0]) => ($LARGESIZE+1)*size;
lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size),
LFS_SEEK_END) => LFS_ERR_INVAL;
lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size;
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"

View File

@@ -8,7 +8,7 @@ LARGESIZE=8192
echo "=== Truncate tests ==="
rm -rf blocks
tests/test.py << TEST
lfs2_format(&lfs2, &cfg) => 0;
lfs_format(&lfs, &cfg) => 0;
TEST
truncate_test() {
@@ -17,98 +17,98 @@ STARTSEEKS="$2"
HOTSIZES="$3"
COLDSIZES="$4"
tests/test.py << TEST
static const lfs2_off_t startsizes[] = {$STARTSIZES};
static const lfs2_off_t startseeks[] = {$STARTSEEKS};
static const lfs2_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t startseeks[] = {$STARTSEEKS};
static const lfs_off_t hotsizes[] = {$HOTSIZES};
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i);
lfs2_file_open(&lfs2, &file[0], (const char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file[0], (const char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
strcpy((char*)buffer, "hair");
size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < startsizes[i]; j += size) {
lfs2_file_write(&lfs2, &file[0], buffer, size) => size;
for (int j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file[0], buffer, size) => size;
}
lfs2_file_size(&lfs2, &file[0]) => startsizes[i];
lfs_file_size(&lfs, &file[0]) => startsizes[i];
if (startseeks[i] != startsizes[i]) {
lfs2_file_seek(&lfs2, &file[0],
startseeks[i], LFS2_SEEK_SET) => startseeks[i];
lfs_file_seek(&lfs, &file[0],
startseeks[i], LFS_SEEK_SET) => startseeks[i];
}
lfs2_file_truncate(&lfs2, &file[0], hotsizes[i]) => 0;
lfs2_file_size(&lfs2, &file[0]) => hotsizes[i];
lfs_file_truncate(&lfs, &file[0], hotsizes[i]) => 0;
lfs_file_size(&lfs, &file[0]) => hotsizes[i];
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
static const lfs2_off_t startsizes[] = {$STARTSIZES};
static const lfs2_off_t hotsizes[] = {$HOTSIZES};
static const lfs2_off_t coldsizes[] = {$COLDSIZES};
static const lfs_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t coldsizes[] = {$COLDSIZES};
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i);
lfs2_file_open(&lfs2, &file[0], (const char*)buffer, LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file[0]) => hotsizes[i];
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file[0]) => hotsizes[i];
size = strlen("hair");
lfs2_off_t j = 0;
int j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
for (; j < hotsizes[i]; j += size) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0;
}
lfs2_file_truncate(&lfs2, &file[0], coldsizes[i]) => 0;
lfs2_file_size(&lfs2, &file[0]) => coldsizes[i];
lfs_file_truncate(&lfs, &file[0], coldsizes[i]) => 0;
lfs_file_size(&lfs, &file[0]) => coldsizes[i];
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
tests/test.py << TEST
static const lfs2_off_t startsizes[] = {$STARTSIZES};
static const lfs2_off_t hotsizes[] = {$HOTSIZES};
static const lfs2_off_t coldsizes[] = {$COLDSIZES};
static const lfs_off_t startsizes[] = {$STARTSIZES};
static const lfs_off_t hotsizes[] = {$HOTSIZES};
static const lfs_off_t coldsizes[] = {$COLDSIZES};
lfs2_mount(&lfs2, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0;
for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) {
sprintf((char*)buffer, "hairyhead%d", i);
lfs2_file_open(&lfs2, &file[0], (const char*)buffer, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file[0]) => coldsizes[i];
lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file[0]) => coldsizes[i];
size = strlen("hair");
lfs2_off_t j = 0;
int j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
for (; j < coldsizes[i]; j += size) {
lfs2_file_read(&lfs2, &file[0], buffer, size) => size;
lfs_file_read(&lfs, &file[0], buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0;
}
lfs2_file_close(&lfs2, &file[0]) => 0;
lfs_file_close(&lfs, &file[0]) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
TEST
}