mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Compare commits
	
		
			35 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7127786d39 | ||
|  | 9c7e232086 | ||
|  | c676bcee4c | ||
|  | 03f088b92c | ||
|  | e955b9f65d | ||
|  | 99f58139cb | ||
|  | 5801169348 | ||
|  | 2d6f4ead13 | ||
|  | 3d1b89b41a | ||
|  | 45cefb825d | ||
|  | bbb9e3873e | ||
|  | c6d3c48939 | ||
|  | 1363c9f9d4 | ||
|  | 5bc682a0d4 | ||
|  | 1877c40aac | ||
|  | e29e7aeefa | ||
|  | 4977fa0c0e | ||
|  | fdda3b4aa2 | ||
|  | fb2c311bb4 | ||
|  | 4dcad66e16 | ||
|  | b816d7f898 | ||
|  | c40271bcf3 | ||
|  | 197ad15e47 | ||
|  | 3e7b9da578 | ||
|  | 1f204e6d84 | ||
|  | 893325aeb9 | ||
|  | c39b1de658 | ||
|  | f3608e84c7 | ||
|  | c08e977799 | ||
|  | bc7be77625 | ||
|  | 96c8b6dcb3 | ||
|  | 895767cc9d | ||
|  | 87d3abba61 | ||
|  | 19f4eae52c | ||
|  | 8d4fd46a4c | 
							
								
								
									
										62
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -36,44 +36,44 @@ jobs: | ||||
|  | ||||
|       - name: find-version | ||||
|         run: | | ||||
|           # rip version from lfs.h | ||||
|           LFS_VERSION="$(grep -o '^#define LFS_VERSION .*$' lfs.h \ | ||||
|           # rip version from lfs2.h | ||||
|           LFS2_VERSION="$(grep -o '^#define LFS2_VERSION .*$' lfs2.h \ | ||||
|             | awk '{print $3}')" | ||||
|           LFS_VERSION_MAJOR="$((0xffff & ($LFS_VERSION >> 16)))" | ||||
|           LFS_VERSION_MINOR="$((0xffff & ($LFS_VERSION >>  0)))" | ||||
|           LFS2_VERSION_MAJOR="$((0xffff & ($LFS2_VERSION >> 16)))" | ||||
|           LFS2_VERSION_MINOR="$((0xffff & ($LFS2_VERSION >>  0)))" | ||||
|  | ||||
|           # find a new patch version based on what we find in our tags | ||||
|           LFS_VERSION_PATCH="$( \ | ||||
|           LFS2_VERSION_PATCH="$( \ | ||||
|             ( git describe --tags --abbrev=0 \ | ||||
|                 --match="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.*" \ | ||||
|                 --match="v$LFS2_VERSION_MAJOR.$LFS2_VERSION_MINOR.*" \ | ||||
|               || echo 'v0.0.-1' ) \ | ||||
|             | awk -F '.' '{print $3+1}')" | ||||
|  | ||||
|           # found new version | ||||
|           LFS_VERSION="v$LFS_VERSION_MAJOR` | ||||
|             `.$LFS_VERSION_MINOR` | ||||
|             `.$LFS_VERSION_PATCH" | ||||
|           echo "LFS_VERSION=$LFS_VERSION" | ||||
|           echo "LFS_VERSION=$LFS_VERSION" >> $GITHUB_ENV | ||||
|           echo "LFS_VERSION_MAJOR=$LFS_VERSION_MAJOR" >> $GITHUB_ENV | ||||
|           echo "LFS_VERSION_MINOR=$LFS_VERSION_MINOR" >> $GITHUB_ENV | ||||
|           echo "LFS_VERSION_PATCH=$LFS_VERSION_PATCH" >> $GITHUB_ENV | ||||
|           LFS2_VERSION="v$LFS2_VERSION_MAJOR` | ||||
|             `.$LFS2_VERSION_MINOR` | ||||
|             `.$LFS2_VERSION_PATCH" | ||||
|           echo "LFS2_VERSION=$LFS2_VERSION" | ||||
|           echo "LFS2_VERSION=$LFS2_VERSION" >> $GITHUB_ENV | ||||
|           echo "LFS2_VERSION_MAJOR=$LFS2_VERSION_MAJOR" >> $GITHUB_ENV | ||||
|           echo "LFS2_VERSION_MINOR=$LFS2_VERSION_MINOR" >> $GITHUB_ENV | ||||
|           echo "LFS2_VERSION_PATCH=$LFS2_VERSION_PATCH" >> $GITHUB_ENV | ||||
|  | ||||
|       # try to find previous version? | ||||
|       - name: find-prev-version | ||||
|         continue-on-error: true | ||||
|         run: | | ||||
|           LFS_PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')" | ||||
|           echo "LFS_PREV_VERSION=$LFS_PREV_VERSION" | ||||
|           echo "LFS_PREV_VERSION=$LFS_PREV_VERSION" >> $GITHUB_ENV | ||||
|           LFS2_PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')" | ||||
|           echo "LFS2_PREV_VERSION=$LFS2_PREV_VERSION" | ||||
|           echo "LFS2_PREV_VERSION=$LFS2_PREV_VERSION" >> $GITHUB_ENV | ||||
|  | ||||
|       # try to find results from tests | ||||
|       - name: collect-results | ||||
|         run: | | ||||
|           # previous results to compare against? | ||||
|           [ -n "$LFS_PREV_VERSION" ] && curl -sS \ | ||||
|           [ -n "$LFS2_PREV_VERSION" ] && curl -sS \ | ||||
|             "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/` | ||||
|               `status/$LFS_PREV_VERSION" \ | ||||
|               `status/$LFS2_PREV_VERSION" \ | ||||
|             | jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]' \ | ||||
|             >> prev-results.json \ | ||||
|             || true | ||||
| @@ -161,10 +161,10 @@ jobs: | ||||
|       # find changes from history | ||||
|       - name: collect-changes | ||||
|         run: | | ||||
|           [ -n "$LFS_PREV_VERSION" ] || exit 0 | ||||
|           [ -n "$LFS2_PREV_VERSION" ] || exit 0 | ||||
|           # use explicit link to github commit so that release notes can | ||||
|           # be copied elsewhere | ||||
|           git log "$LFS_PREV_VERSION.." \ | ||||
|           git log "$LFS2_PREV_VERSION.." \ | ||||
|             --grep='^Merge' --invert-grep \ | ||||
|             --format="format:[\`%h\`](` | ||||
|               `https://github.com/$GITHUB_REPOSITORY/commit/%h) %s" \ | ||||
| @@ -176,25 +176,25 @@ jobs: | ||||
|       - name: create-major-branches | ||||
|         run: | | ||||
|           # create major branch | ||||
|           git branch "v$LFS_VERSION_MAJOR" HEAD | ||||
|           git branch "v$LFS2_VERSION_MAJOR" HEAD | ||||
|  | ||||
|           # create major prefix branch | ||||
|           git config user.name ${{secrets.BOT_USER}} | ||||
|           git config user.email ${{secrets.BOT_EMAIL}} | ||||
|           git fetch "https://github.com/$GITHUB_REPOSITORY.git" \ | ||||
|             "v$LFS_VERSION_MAJOR-prefix" || true | ||||
|           ./scripts/prefix.py "lfs$LFS_VERSION_MAJOR" | ||||
|           git branch "v$LFS_VERSION_MAJOR-prefix" $( \ | ||||
|             "v$LFS2_VERSION_MAJOR-prefix" || true | ||||
|           ./scripts/prefix.py "lfs2$LFS2_VERSION_MAJOR" | ||||
|           git branch "v$LFS2_VERSION_MAJOR-prefix" $( \ | ||||
|             git commit-tree $(git write-tree) \ | ||||
|               $(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \ | ||||
|               -p HEAD \ | ||||
|               -m "Generated v$LFS_VERSION_MAJOR prefixes") | ||||
|               -m "Generated v$LFS2_VERSION_MAJOR prefixes") | ||||
|           git reset --hard | ||||
|  | ||||
|           # push! | ||||
|           git push --atomic origin \ | ||||
|             "v$LFS_VERSION_MAJOR" \ | ||||
|             "v$LFS_VERSION_MAJOR-prefix" | ||||
|             "v$LFS2_VERSION_MAJOR" \ | ||||
|             "v$LFS2_VERSION_MAJOR-prefix" | ||||
|  | ||||
|       # build release notes | ||||
|       - name: create-release | ||||
| @@ -206,10 +206,10 @@ jobs: | ||||
|           curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \ | ||||
|             "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases" \ | ||||
|             -d "$(jq -n '{ | ||||
|               tag_name: env.LFS_VERSION, | ||||
|               name: env.LFS_VERSION | rtrimstr(".0"), | ||||
|               tag_name: env.LFS2_VERSION, | ||||
|               name: env.LFS2_VERSION | rtrimstr(".0"), | ||||
|               target_commitish: "${{github.event.workflow_run.head_sha}}", | ||||
|               draft: env.LFS_VERSION | endswith(".0"), | ||||
|               draft: env.LFS2_VERSION | endswith(".0"), | ||||
|               body: [env.RESULTS, env.CHANGES | select(.)] | join("\n\n")}' \ | ||||
|               | tee /dev/stderr)" | ||||
|  | ||||
|   | ||||
							
								
								
									
										74
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							| @@ -96,25 +96,25 @@ jobs: | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096" | ||||
|             -DLFS2_READ_SIZE=1 -DLFS2_BLOCK_SIZE=4096" | ||||
|       # SD/eMMC: read/prog = 512 block = 512 | ||||
|       - name: test-emmc | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512" | ||||
|             -DLFS2_READ_SIZE=512 -DLFS2_BLOCK_SIZE=512" | ||||
|       # NAND flash: read/prog = 4KiB block = 32KiB | ||||
|       - name: test-nand | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)" | ||||
|             -DLFS2_READ_SIZE=4096 -DLFS2_BLOCK_SIZE=\(32*1024\)" | ||||
|       # other extreme geometries that are useful for various corner cases | ||||
|       - name: test-no-intrinsics | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_NO_INTRINSICS" | ||||
|             -DLFS2_NO_INTRINSICS" | ||||
|       - name: test-byte-writes | ||||
|         # it just takes too long to test byte-level writes when in qemu, | ||||
|         # should be plenty covered by the other configurations | ||||
| @@ -122,22 +122,22 @@ jobs: | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1" | ||||
|             -DLFS2_READ_SIZE=1 -DLFS2_CACHE_SIZE=1" | ||||
|       - name: test-block-cycles | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_BLOCK_CYCLES=1" | ||||
|             -DLFS2_BLOCK_CYCLES=1" | ||||
|       - name: test-odd-block-count | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" | ||||
|             -DLFS2_BLOCK_COUNT=1023 -DLFS2_LOOKAHEAD_SIZE=256" | ||||
|       - name: test-odd-block-size | ||||
|         run: | | ||||
|           make clean | ||||
|           make test TESTFLAGS+="-nrk \ | ||||
|             -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704" | ||||
|             -DLFS2_READ_SIZE=11 -DLFS2_BLOCK_SIZE=704" | ||||
|  | ||||
|       # upload coverage for later coverage | ||||
|       - name: upload-coverage | ||||
| @@ -154,10 +154,10 @@ jobs: | ||||
|           make clean | ||||
|           make code \ | ||||
|             CFLAGS+=" \ | ||||
|               -DLFS_NO_ASSERT \ | ||||
|               -DLFS_NO_DEBUG \ | ||||
|               -DLFS_NO_WARN \ | ||||
|               -DLFS_NO_ERROR" \ | ||||
|               -DLFS2_NO_ASSERT \ | ||||
|               -DLFS2_NO_DEBUG \ | ||||
|               -DLFS2_NO_WARN \ | ||||
|               -DLFS2_NO_ERROR" \ | ||||
|             CODEFLAGS+="-o results/code-${{matrix.arch}}.csv" | ||||
|       - name: results-code-readonly | ||||
|         run: | | ||||
| @@ -165,11 +165,11 @@ jobs: | ||||
|           make clean | ||||
|           make code \ | ||||
|             CFLAGS+=" \ | ||||
|               -DLFS_NO_ASSERT \ | ||||
|               -DLFS_NO_DEBUG \ | ||||
|               -DLFS_NO_WARN \ | ||||
|               -DLFS_NO_ERROR \ | ||||
|               -DLFS_READONLY" \ | ||||
|               -DLFS2_NO_ASSERT \ | ||||
|               -DLFS2_NO_DEBUG \ | ||||
|               -DLFS2_NO_WARN \ | ||||
|               -DLFS2_NO_ERROR \ | ||||
|               -DLFS2_READONLY" \ | ||||
|             CODEFLAGS+="-o results/code-${{matrix.arch}}-readonly.csv" | ||||
|       - name: results-code-threadsafe | ||||
|         run: | | ||||
| @@ -177,11 +177,11 @@ jobs: | ||||
|           make clean | ||||
|           make code \ | ||||
|             CFLAGS+=" \ | ||||
|               -DLFS_NO_ASSERT \ | ||||
|               -DLFS_NO_DEBUG \ | ||||
|               -DLFS_NO_WARN \ | ||||
|               -DLFS_NO_ERROR \ | ||||
|               -DLFS_THREADSAFE" \ | ||||
|               -DLFS2_NO_ASSERT \ | ||||
|               -DLFS2_NO_DEBUG \ | ||||
|               -DLFS2_NO_WARN \ | ||||
|               -DLFS2_NO_ERROR \ | ||||
|               -DLFS2_THREADSAFE" \ | ||||
|             CODEFLAGS+="-o results/code-${{matrix.arch}}-threadsafe.csv" | ||||
|       - name: results-code-migrate | ||||
|         run: | | ||||
| @@ -189,11 +189,11 @@ jobs: | ||||
|           make clean | ||||
|           make code \ | ||||
|             CFLAGS+=" \ | ||||
|               -DLFS_NO_ASSERT \ | ||||
|               -DLFS_NO_DEBUG \ | ||||
|               -DLFS_NO_WARN \ | ||||
|               -DLFS_NO_ERROR \ | ||||
|               -DLFS_MIGRATE" \ | ||||
|               -DLFS2_NO_ASSERT \ | ||||
|               -DLFS2_NO_DEBUG \ | ||||
|               -DLFS2_NO_WARN \ | ||||
|               -DLFS2_NO_ERROR \ | ||||
|               -DLFS2_MIGRATE" \ | ||||
|             CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv" | ||||
|       - name: results-code-error-asserts | ||||
|         run: | | ||||
| @@ -201,10 +201,10 @@ jobs: | ||||
|           make clean | ||||
|           make code \ | ||||
|             CFLAGS+=" \ | ||||
|               -DLFS_NO_DEBUG \ | ||||
|               -DLFS_NO_WARN \ | ||||
|               -DLFS_NO_ERROR \ | ||||
|               -D'LFS_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \ | ||||
|               -DLFS2_NO_DEBUG \ | ||||
|               -DLFS2_NO_WARN \ | ||||
|               -DLFS2_NO_ERROR \ | ||||
|               -D'LFS2_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \ | ||||
|             CODEFLAGS+="-o results/code-${{matrix.arch}}-error-asserts.csv" | ||||
|       - name: upload-results | ||||
|         uses: actions/upload-artifact@v2 | ||||
| @@ -305,8 +305,8 @@ jobs: | ||||
|           # self-host test | ||||
|           make -C littlefs-fuse | ||||
|  | ||||
|           littlefs-fuse/lfs --format /dev/loop0 | ||||
|           littlefs-fuse/lfs /dev/loop0 mount | ||||
|           littlefs-fuse/lfs2 --format /dev/loop0 | ||||
|           littlefs-fuse/lfs2 /dev/loop0 mount | ||||
|  | ||||
|           ls mount | ||||
|           mkdir mount/littlefs | ||||
| @@ -358,8 +358,8 @@ jobs: | ||||
|           make -C v2 | ||||
|  | ||||
|           # run self-host test with v1 | ||||
|           v1/lfs --format /dev/loop0 | ||||
|           v1/lfs /dev/loop0 mount | ||||
|           v1/lfs2 --format /dev/loop0 | ||||
|           v1/lfs2 /dev/loop0 mount | ||||
|  | ||||
|           ls mount | ||||
|           mkdir mount/littlefs | ||||
| @@ -373,8 +373,8 @@ jobs: | ||||
|           cd ../.. | ||||
|           fusermount -u mount | ||||
|  | ||||
|           v2/lfs --migrate /dev/loop0 | ||||
|           v2/lfs /dev/loop0 mount | ||||
|           v2/lfs2 --migrate /dev/loop0 | ||||
|           v2/lfs2 /dev/loop0 mount | ||||
|  | ||||
|           # run self-host test with v2 right where we left off | ||||
|           ls mount | ||||
|   | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| # Testing things | ||||
| blocks/ | ||||
| lfs | ||||
| lfs2 | ||||
| test.c | ||||
| tests/*.toml.* | ||||
| scripts/__pycache__ | ||||
|   | ||||
							
								
								
									
										8
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Makefile
									
									
									
									
									
								
							| @@ -11,9 +11,9 @@ endif | ||||
|  | ||||
| # overridable target/src/tools/flags/etc | ||||
| ifneq ($(wildcard test.c main.c),) | ||||
| TARGET ?= $(BUILDDIR)lfs | ||||
| TARGET ?= $(BUILDDIR)lfs2 | ||||
| else | ||||
| TARGET ?= $(BUILDDIR)lfs.a | ||||
| TARGET ?= $(BUILDDIR)lfs2.a | ||||
| endif | ||||
|  | ||||
|  | ||||
| @@ -35,7 +35,7 @@ else | ||||
| override CFLAGS += -Os | ||||
| endif | ||||
| ifdef TRACE | ||||
| override CFLAGS += -DLFS_YES_TRACE | ||||
| override CFLAGS += -DLFS2_YES_TRACE | ||||
| endif | ||||
| override CFLAGS += -I. | ||||
| override CFLAGS += -std=c99 -Wall -pedantic | ||||
| @@ -92,7 +92,7 @@ coverage: | ||||
| -include $(DEP) | ||||
| .SUFFIXES: | ||||
|  | ||||
| $(BUILDDIR)lfs: $(OBJ) | ||||
| $(BUILDDIR)lfs2: $(OBJ) | ||||
| 	$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ | ||||
|  | ||||
| $(BUILDDIR)%.a: $(OBJ) | ||||
|   | ||||
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							| @@ -32,14 +32,14 @@ main runs. The program can be interrupted at any time without losing track | ||||
| of how many times it has been booted and without corrupting the filesystem: | ||||
|  | ||||
| ``` c | ||||
| #include "lfs.h" | ||||
| #include "lfs2.h" | ||||
|  | ||||
| // variables used by the filesystem | ||||
| lfs_t lfs; | ||||
| lfs_file_t file; | ||||
| lfs2_t lfs2; | ||||
| lfs2_file_t file; | ||||
|  | ||||
| // configuration of the filesystem is provided by this struct | ||||
| const struct lfs_config cfg = { | ||||
| const struct lfs2_config cfg = { | ||||
|     // block device operations | ||||
|     .read  = user_provided_block_device_read, | ||||
|     .prog  = user_provided_block_device_prog, | ||||
| @@ -59,30 +59,30 @@ const struct lfs_config cfg = { | ||||
| // entry point | ||||
| int main(void) { | ||||
|     // mount the filesystem | ||||
|     int err = lfs_mount(&lfs, &cfg); | ||||
|     int err = lfs2_mount(&lfs2, &cfg); | ||||
|  | ||||
|     // reformat if we can't mount the filesystem | ||||
|     // this should only happen on the first boot | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg); | ||||
|         lfs_mount(&lfs, &cfg); | ||||
|         lfs2_format(&lfs2, &cfg); | ||||
|         lfs2_mount(&lfs2, &cfg); | ||||
|     } | ||||
|  | ||||
|     // read current count | ||||
|     uint32_t boot_count = 0; | ||||
|     lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); | ||||
|     lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); | ||||
|     lfs2_file_open(&lfs2, &file, "boot_count", LFS2_O_RDWR | LFS2_O_CREAT); | ||||
|     lfs2_file_read(&lfs2, &file, &boot_count, sizeof(boot_count)); | ||||
|  | ||||
|     // update boot count | ||||
|     boot_count += 1; | ||||
|     lfs_file_rewind(&lfs, &file); | ||||
|     lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count)); | ||||
|     lfs2_file_rewind(&lfs2, &file); | ||||
|     lfs2_file_write(&lfs2, &file, &boot_count, sizeof(boot_count)); | ||||
|  | ||||
|     // remember the storage is not updated until the file is closed successfully | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|  | ||||
|     // release any resources we were using | ||||
|     lfs_unmount(&lfs); | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     // print the boot count | ||||
|     printf("boot_count: %d\n", boot_count); | ||||
| @@ -92,7 +92,7 @@ int main(void) { | ||||
| ## Usage | ||||
|  | ||||
| Detailed documentation (or at least as much detail as is currently available) | ||||
| can be found in the comments in [lfs.h](lfs.h). | ||||
| can be found in the comments in [lfs2.h](lfs2.h). | ||||
|  | ||||
| littlefs takes in a configuration structure that defines how the filesystem | ||||
| operates. The configuration struct provides the filesystem with the block | ||||
| @@ -100,9 +100,9 @@ device operations and dimensions, tweakable parameters that tradeoff memory | ||||
| usage for performance, and optional static buffers if the user wants to avoid | ||||
| dynamic memory. | ||||
|  | ||||
| The state of the littlefs is stored in the `lfs_t` type which is left up | ||||
| The state of the littlefs is stored in the `lfs2_t` type which is left up | ||||
| to the user to allocate, allowing multiple filesystems to be in use | ||||
| simultaneously. With the `lfs_t` and configuration struct, a user can | ||||
| simultaneously. With the `lfs2_t` and configuration struct, a user can | ||||
| format a block device or mount the filesystem. | ||||
|  | ||||
| Once mounted, the littlefs provides a full set of POSIX-like file and | ||||
| @@ -119,11 +119,11 @@ Littlefs is written in C, and specifically should compile with any compiler | ||||
| that conforms to the `C99` standard. | ||||
|  | ||||
| All littlefs calls have the potential to return a negative error code. The | ||||
| errors can be either one of those found in the `enum lfs_error` in | ||||
| [lfs.h](lfs.h), or an error returned by the user's block device operations. | ||||
| errors can be either one of those found in the `enum lfs2_error` in | ||||
| [lfs2.h](lfs2.h), or an error returned by the user's block device operations. | ||||
|  | ||||
| In the configuration struct, the `prog` and `erase` function provided by the | ||||
| user may return a `LFS_ERR_CORRUPT` error if the implementation already can | ||||
| user may return a `LFS2_ERR_CORRUPT` error if the implementation already can | ||||
| detect corrupt blocks. However, the wear leveling does not depend on the return | ||||
| code of these functions, instead all data is read back and checked for | ||||
| integrity. | ||||
| @@ -192,7 +192,7 @@ More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and | ||||
| ## Testing | ||||
|  | ||||
| The littlefs comes with a test suite designed to run on a PC using the | ||||
| [emulated block device](bd/lfs_testbd.h) found in the `bd` directory. | ||||
| [emulated block device](bd/lfs2_testbd.h) found in the `bd` directory. | ||||
| The tests assume a Linux environment and can be started with make: | ||||
|  | ||||
| ``` bash | ||||
|   | ||||
							
								
								
									
										48
									
								
								SPEC.md
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								SPEC.md
									
									
									
									
									
								
							| @@ -233,19 +233,19 @@ Metadata tag fields: | ||||
|    into a 3-bit abstract type and an 8-bit chunk field. Note that the value | ||||
|    `0x000` is invalid and not assigned a type. | ||||
|  | ||||
| 3. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into | ||||
|    8 categories that facilitate bitmasked lookups. | ||||
|     1. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into | ||||
|        8 categories that facilitate bitmasked lookups. | ||||
|  | ||||
| 4. **Chunk (8-bits)** - Chunk field used for various purposes by the different | ||||
|    abstract types.  type1+chunk+id form a unique identifier for each tag in the | ||||
|    metadata block. | ||||
|     2. **Chunk (8-bits)** - Chunk field used for various purposes by the different | ||||
|        abstract types.  type1+chunk+id form a unique identifier for each tag in the | ||||
|        metadata block. | ||||
|  | ||||
| 5. **Id (10-bits)** - File id associated with the tag. Each file in a metadata | ||||
| 3. **Id (10-bits)** - File id associated with the tag. Each file in a metadata | ||||
|    block gets a unique id which is used to associate tags with that file. The | ||||
|    special value `0x3ff` is used for any tags that are not associated with a | ||||
|    file, such as directory and global metadata. | ||||
|  | ||||
| 6. **Length (10-bits)** - Length of the data in bytes. The special value | ||||
| 4. **Length (10-bits)** - Length of the data in bytes. The special value | ||||
|    `0x3ff` indicates that this tag has been deleted. | ||||
|  | ||||
| ## Metadata types | ||||
| @@ -253,7 +253,7 @@ Metadata tag fields: | ||||
| What follows is an exhaustive list of metadata in littlefs. | ||||
|  | ||||
| --- | ||||
| #### `0x401` LFS_TYPE_CREATE | ||||
| #### `0x401` LFS2_TYPE_CREATE | ||||
|  | ||||
| Creates a new file with this id. Note that files in a metadata block | ||||
| don't necessarily need a create tag. All a create does is move over any | ||||
| @@ -264,14 +264,14 @@ The create and delete tags allow littlefs to keep files in a directory | ||||
| ordered alphabetically by filename. | ||||
|  | ||||
| --- | ||||
| #### `0x4ff` LFS_TYPE_DELETE | ||||
| #### `0x4ff` LFS2_TYPE_DELETE | ||||
|  | ||||
| Deletes the file with this id. An inverse to create, this tag moves over | ||||
| any files neighboring this id similar to a deletion from an imaginary | ||||
| array of files. | ||||
|  | ||||
| --- | ||||
| #### `0x0xx` LFS_TYPE_NAME | ||||
| #### `0x0xx` LFS2_TYPE_NAME | ||||
|  | ||||
| Associates the id with a file name and file type. | ||||
|  | ||||
| @@ -304,14 +304,14 @@ Name fields: | ||||
| 2. **file name** - File name stored as an ASCII string. | ||||
|  | ||||
| --- | ||||
| #### `0x001` LFS_TYPE_REG | ||||
| #### `0x001` LFS2_TYPE_REG | ||||
|  | ||||
| Initializes the id + name as a regular file. | ||||
|  | ||||
| How each file is stored depends on its struct tag, which is described below. | ||||
|  | ||||
| --- | ||||
| #### `0x002` LFS_TYPE_DIR | ||||
| #### `0x002` LFS2_TYPE_DIR | ||||
|  | ||||
| Initializes the id + name as a directory. | ||||
|  | ||||
| @@ -320,7 +320,7 @@ each pair containing any number of files in alphabetical order. A pointer to | ||||
| the directory is stored in the struct tag, which is described below. | ||||
|  | ||||
| --- | ||||
| #### `0x0ff` LFS_TYPE_SUPERBLOCK | ||||
| #### `0x0ff` LFS2_TYPE_SUPERBLOCK | ||||
|  | ||||
| Initializes the id as a superblock entry. | ||||
|  | ||||
| @@ -405,7 +405,7 @@ as be the first entry written to the block. This means that the superblock | ||||
| entry can be read from a device using offsets alone. | ||||
|  | ||||
| --- | ||||
| #### `0x2xx` LFS_TYPE_STRUCT | ||||
| #### `0x2xx` LFS2_TYPE_STRUCT | ||||
|  | ||||
| Associates the id with an on-disk data structure. | ||||
|  | ||||
| @@ -416,7 +416,7 @@ Any type of struct supersedes all other structs associated with the id. For | ||||
| example, appending a ctz-struct replaces an inline-struct on the same file. | ||||
|  | ||||
| --- | ||||
| #### `0x200` LFS_TYPE_DIRSTRUCT | ||||
| #### `0x200` LFS2_TYPE_DIRSTRUCT | ||||
|  | ||||
| Gives the id a directory data structure. | ||||
|  | ||||
| @@ -458,7 +458,7 @@ Dir-struct fields: | ||||
|    in the directory. | ||||
|  | ||||
| --- | ||||
| #### `0x201` LFS_TYPE_INLINESTRUCT | ||||
| #### `0x201` LFS2_TYPE_INLINESTRUCT | ||||
|  | ||||
| Gives the id an inline data structure. | ||||
|  | ||||
| @@ -482,7 +482,7 @@ Inline-struct fields: | ||||
| 1. **Inline data** - File data stored directly in the metadata-pair. | ||||
|  | ||||
| --- | ||||
| #### `0x202` LFS_TYPE_CTZSTRUCT | ||||
| #### `0x202` LFS2_TYPE_CTZSTRUCT | ||||
|  | ||||
| Gives the id a CTZ skip-list data structure. | ||||
|  | ||||
| @@ -537,7 +537,7 @@ CTZ-struct fields: | ||||
| 2. **File size (32-bits)** - Size of the file in bytes. | ||||
|  | ||||
| --- | ||||
| #### `0x3xx` LFS_TYPE_USERATTR | ||||
| #### `0x3xx` LFS2_TYPE_USERATTR | ||||
|  | ||||
| Attaches a user attribute to an id. | ||||
|  | ||||
| @@ -571,7 +571,7 @@ User-attr fields: | ||||
| 2. **Attr data** - The data associated with the user attribute. | ||||
|  | ||||
| --- | ||||
| #### `0x6xx` LFS_TYPE_TAIL | ||||
| #### `0x6xx` LFS2_TYPE_TAIL | ||||
|  | ||||
| Provides the tail pointer for the metadata pair itself. | ||||
|  | ||||
| @@ -637,7 +637,7 @@ Tail fields: | ||||
| 2. **Metadata pair (8-bytes)** - Pointer to the next metadata-pair. | ||||
|  | ||||
| --- | ||||
| #### `0x600` LFS_TYPE_SOFTTAIL | ||||
| #### `0x600` LFS2_TYPE_SOFTTAIL | ||||
|  | ||||
| Provides a tail pointer that points to the next metadata pair in the | ||||
| filesystem. | ||||
| @@ -646,7 +646,7 @@ In this case, the next metadata pair is not a part of our current directory | ||||
| and should only be followed when traversing the entire filesystem. | ||||
|  | ||||
| --- | ||||
| #### `0x601` LFS_TYPE_HARDTAIL | ||||
| #### `0x601` LFS2_TYPE_HARDTAIL | ||||
|  | ||||
| Provides a tail pointer that points to the next metadata pair in the | ||||
| directory. | ||||
| @@ -657,7 +657,7 @@ metadata pair should only contain filenames greater than any filename in the | ||||
| current pair. | ||||
|  | ||||
| --- | ||||
| #### `0x7xx` LFS_TYPE_GSTATE | ||||
| #### `0x7xx` LFS2_TYPE_GSTATE | ||||
|  | ||||
| Provides delta bits for global state entries. | ||||
|  | ||||
| @@ -687,7 +687,7 @@ is stored in the chunk field. Currently, the only global state is move state, | ||||
| which is outlined below. | ||||
|  | ||||
| --- | ||||
| #### `0x7ff` LFS_TYPE_MOVESTATE | ||||
| #### `0x7ff` LFS2_TYPE_MOVESTATE | ||||
|  | ||||
| Provides delta bits for the global move state. | ||||
|  | ||||
| @@ -740,7 +740,7 @@ Move state fields: | ||||
|    the move. | ||||
|  | ||||
| --- | ||||
| #### `0x5xx` LFS_TYPE_CRC | ||||
| #### `0x5xx` LFS2_TYPE_CRC | ||||
|  | ||||
| Last but not least, the CRC tag marks the end of a commit and provides a | ||||
| checksum for any commits to the metadata block. | ||||
|   | ||||
| @@ -4,15 +4,15 @@ | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "bd/lfs_filebd.h" | ||||
| #include "bd/lfs2_filebd.h" | ||||
| 
 | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, | ||||
|         const struct lfs_filebd_config *bdcfg) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, " | ||||
| int lfs2_filebd_createcfg(const struct lfs2_config *cfg, const char *path, | ||||
|         const struct lfs2_filebd_config *bdcfg) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_createcfg(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
| @@ -23,23 +23,23 @@ int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             path, (void*)bdcfg, bdcfg->erase_value); | ||||
|     lfs_filebd_t *bd = cfg->context; | ||||
|     lfs2_filebd_t *bd = cfg->context; | ||||
|     bd->cfg = bdcfg; | ||||
| 
 | ||||
|     // open file
 | ||||
|     bd->fd = open(path, O_RDWR | O_CREAT, 0666); | ||||
|     if (bd->fd < 0) { | ||||
|         int err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", err); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_createcfg -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", 0); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_createcfg -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, " | ||||
| int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_create(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
| @@ -49,38 +49,38 @@ int lfs_filebd_create(const struct lfs_config *cfg, const char *path) { | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             path); | ||||
|     static const struct lfs_filebd_config defaults = {.erase_value=-1}; | ||||
|     int err = lfs_filebd_createcfg(cfg, path, &defaults); | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err); | ||||
|     static const struct lfs2_filebd_config defaults = {.erase_value=-1}; | ||||
|     int err = lfs2_filebd_createcfg(cfg, path, &defaults); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_create -> %d", err); | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| int lfs_filebd_destroy(const struct lfs_config *cfg) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg); | ||||
|     lfs_filebd_t *bd = cfg->context; | ||||
| int lfs2_filebd_destroy(const struct lfs2_config *cfg) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_destroy(%p)", (void*)cfg); | ||||
|     lfs2_filebd_t *bd = cfg->context; | ||||
|     int err = close(bd->fd); | ||||
|     if (err < 0) { | ||||
|         err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", err); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_destroy -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", 0); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_destroy -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_read(%p, " | ||||
| int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_read(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs_filebd_t *bd = cfg->context; | ||||
|     lfs2_filebd_t *bd = cfg->context; | ||||
| 
 | ||||
|     // check if read is valid
 | ||||
|     LFS_ASSERT(off  % cfg->read_size == 0); | ||||
|     LFS_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|     LFS2_ASSERT(off  % cfg->read_size == 0); | ||||
|     LFS2_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
| 
 | ||||
|     // zero for reproducability (in case file is truncated)
 | ||||
|     // zero for reproducibility (in case file is truncated)
 | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
|         memset(buffer, bd->cfg->erase_value, size); | ||||
|     } | ||||
| @@ -90,31 +90,31 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); | ||||
|     if (res1 < 0) { | ||||
|         int err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     ssize_t res2 = read(bd->fd, buffer, size); | ||||
|     if (res2 < 0) { | ||||
|         int err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
| int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs_filebd_t *bd = cfg->context; | ||||
|     lfs2_filebd_t *bd = cfg->context; | ||||
| 
 | ||||
|     // check if write is valid
 | ||||
|     LFS_ASSERT(off  % cfg->prog_size == 0); | ||||
|     LFS_ASSERT(size % cfg->prog_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|     LFS2_ASSERT(off  % cfg->prog_size == 0); | ||||
|     LFS2_ASSERT(size % cfg->prog_size == 0); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
| 
 | ||||
|     // check that data was erased? only needed for testing
 | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
| @@ -122,20 +122,20 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|                 (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); | ||||
|         if (res1 < 0) { | ||||
|             int err = -errno; | ||||
|             LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); | ||||
|             LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err); | ||||
|             return err; | ||||
|         } | ||||
| 
 | ||||
|         for (lfs_off_t i = 0; i < size; i++) { | ||||
|         for (lfs2_off_t i = 0; i < size; i++) { | ||||
|             uint8_t c; | ||||
|             ssize_t res2 = read(bd->fd, &c, 1); | ||||
|             if (res2 < 0) { | ||||
|                 int err = -errno; | ||||
|                 LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); | ||||
|                 LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err); | ||||
|                 return err; | ||||
|             } | ||||
| 
 | ||||
|             LFS_ASSERT(c == bd->cfg->erase_value); | ||||
|             LFS2_ASSERT(c == bd->cfg->erase_value); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @@ -144,62 +144,62 @@ int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); | ||||
|     if (res1 < 0) { | ||||
|         int err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     ssize_t res2 = write(bd->fd, buffer, size); | ||||
|     if (res2 < 0) { | ||||
|         int err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", 0); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||
|     lfs_filebd_t *bd = cfg->context; | ||||
| int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||
|     lfs2_filebd_t *bd = cfg->context; | ||||
| 
 | ||||
|     // check if erase is valid
 | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
| 
 | ||||
|     // erase, only needed for testing
 | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
|         off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET); | ||||
|         if (res1 < 0) { | ||||
|             int err = -errno; | ||||
|             LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); | ||||
|             LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", err); | ||||
|             return err; | ||||
|         } | ||||
| 
 | ||||
|         for (lfs_off_t i = 0; i < cfg->block_size; i++) { | ||||
|         for (lfs2_off_t i = 0; i < cfg->block_size; i++) { | ||||
|             ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1); | ||||
|             if (res2 < 0) { | ||||
|                 int err = -errno; | ||||
|                 LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err); | ||||
|                 LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", err); | ||||
|                 return err; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_filebd_sync(const struct lfs_config *cfg) { | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg); | ||||
| int lfs2_filebd_sync(const struct lfs2_config *cfg) { | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_sync(%p)", (void*)cfg); | ||||
|     // file sync
 | ||||
|     lfs_filebd_t *bd = cfg->context; | ||||
|     lfs2_filebd_t *bd = cfg->context; | ||||
|     int err = fsync(bd->fd); | ||||
|     if (err) { | ||||
|         err = -errno; | ||||
|         LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); | ||||
|         LFS2_FILEBD_TRACE("lfs2_filebd_sync -> %d", 0); | ||||
|         return err; | ||||
|     } | ||||
| 
 | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0); | ||||
|     LFS2_FILEBD_TRACE("lfs2_filebd_sync -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										73
									
								
								bd/lfs2_filebd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								bd/lfs2_filebd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| /* | ||||
|  * Block device emulated in a file | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS2_FILEBD_H | ||||
| #define LFS2_FILEBD_H | ||||
|  | ||||
| #include "lfs2.h" | ||||
| #include "lfs2_util.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Block device specific tracing | ||||
| #ifdef LFS2_FILEBD_YES_TRACE | ||||
| #define LFS2_FILEBD_TRACE(...) LFS2_TRACE(__VA_ARGS__) | ||||
| #else | ||||
| #define LFS2_FILEBD_TRACE(...) | ||||
| #endif | ||||
|  | ||||
| // filebd config (optional) | ||||
| struct lfs2_filebd_config { | ||||
|     // 8-bit erase value to use for simulating erases. -1 does not simulate | ||||
|     // erases, which can speed up testing by avoiding all the extra block-device | ||||
|     // operations to store the erase value. | ||||
|     int32_t erase_value; | ||||
| }; | ||||
|  | ||||
| // filebd state | ||||
| typedef struct lfs2_filebd { | ||||
|     int fd; | ||||
|     const struct lfs2_filebd_config *cfg; | ||||
| } lfs2_filebd_t; | ||||
|  | ||||
|  | ||||
| // Create a file block device using the geometry in lfs2_config | ||||
| int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path); | ||||
| int lfs2_filebd_createcfg(const struct lfs2_config *cfg, const char *path, | ||||
|         const struct lfs2_filebd_config *bdcfg); | ||||
|  | ||||
| // Clean up memory associated with block device | ||||
| int lfs2_filebd_destroy(const struct lfs2_config *cfg); | ||||
|  | ||||
| // Read a block | ||||
| int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size); | ||||
|  | ||||
| // Program a block | ||||
| // | ||||
| // The block must have previously been erased. | ||||
| int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size); | ||||
|  | ||||
| // Erase a block | ||||
| // | ||||
| // A block must be erased before being programmed. The | ||||
| // state of an erased block is undefined. | ||||
| int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block); | ||||
|  | ||||
| // Sync the block device | ||||
| int lfs2_filebd_sync(const struct lfs2_config *cfg); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -4,11 +4,11 @@ | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "bd/lfs_rambd.h" | ||||
| #include "bd/lfs2_rambd.h" | ||||
| 
 | ||||
| int lfs_rambd_createcfg(const struct lfs_config *cfg, | ||||
|         const struct lfs_rambd_config *bdcfg) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg(%p {.context=%p, " | ||||
| int lfs2_rambd_createcfg(const struct lfs2_config *cfg, | ||||
|         const struct lfs2_rambd_config *bdcfg) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_createcfg(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
| @@ -18,32 +18,34 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             (void*)bdcfg, bdcfg->erase_value, bdcfg->buffer); | ||||
|     lfs_rambd_t *bd = cfg->context; | ||||
|     lfs2_rambd_t *bd = cfg->context; | ||||
|     bd->cfg = bdcfg; | ||||
| 
 | ||||
|     // allocate buffer?
 | ||||
|     if (bd->cfg->buffer) { | ||||
|         bd->buffer = bd->cfg->buffer; | ||||
|     } else { | ||||
|         bd->buffer = lfs_malloc(cfg->block_size * cfg->block_count); | ||||
|         bd->buffer = lfs2_malloc(cfg->block_size * cfg->block_count); | ||||
|         if (!bd->buffer) { | ||||
|             LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", LFS_ERR_NOMEM); | ||||
|             return LFS_ERR_NOMEM; | ||||
|             LFS2_RAMBD_TRACE("lfs2_rambd_createcfg -> %d", LFS2_ERR_NOMEM); | ||||
|             return LFS2_ERR_NOMEM; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // zero for reproducability?
 | ||||
|     // zero for reproducibility?
 | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
|         memset(bd->buffer, bd->cfg->erase_value, | ||||
|                 cfg->block_size * cfg->block_count); | ||||
|     } else { | ||||
|         memset(bd->buffer, 0, cfg->block_size * cfg->block_count); | ||||
|     } | ||||
| 
 | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_createcfg -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_rambd_create(const struct lfs_config *cfg) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, " | ||||
| int lfs2_rambd_create(const struct lfs2_config *cfg) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_create(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"})", | ||||
| @@ -51,58 +53,58 @@ int lfs_rambd_create(const struct lfs_config *cfg) { | ||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count); | ||||
|     static const struct lfs_rambd_config defaults = {.erase_value=-1}; | ||||
|     int err = lfs_rambd_createcfg(cfg, &defaults); | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_create -> %d", err); | ||||
|     static const struct lfs2_rambd_config defaults = {.erase_value=-1}; | ||||
|     int err = lfs2_rambd_createcfg(cfg, &defaults); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_create -> %d", err); | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| int lfs_rambd_destroy(const struct lfs_config *cfg) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg); | ||||
| int lfs2_rambd_destroy(const struct lfs2_config *cfg) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_destroy(%p)", (void*)cfg); | ||||
|     // clean up memory
 | ||||
|     lfs_rambd_t *bd = cfg->context; | ||||
|     lfs2_rambd_t *bd = cfg->context; | ||||
|     if (!bd->cfg->buffer) { | ||||
|         lfs_free(bd->buffer); | ||||
|         lfs2_free(bd->buffer); | ||||
|     } | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_destroy -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_read(%p, " | ||||
| int lfs2_rambd_read(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_read(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs_rambd_t *bd = cfg->context; | ||||
|     lfs2_rambd_t *bd = cfg->context; | ||||
| 
 | ||||
|     // check if read is valid
 | ||||
|     LFS_ASSERT(off  % cfg->read_size == 0); | ||||
|     LFS_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|     LFS2_ASSERT(off  % cfg->read_size == 0); | ||||
|     LFS2_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
| 
 | ||||
|     // read data
 | ||||
|     memcpy(buffer, &bd->buffer[block*cfg->block_size + off], size); | ||||
| 
 | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_read -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_prog(%p, " | ||||
| int lfs2_rambd_prog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_prog(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs_rambd_t *bd = cfg->context; | ||||
|     lfs2_rambd_t *bd = cfg->context; | ||||
| 
 | ||||
|     // check if write is valid
 | ||||
|     LFS_ASSERT(off  % cfg->prog_size == 0); | ||||
|     LFS_ASSERT(size % cfg->prog_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|     LFS2_ASSERT(off  % cfg->prog_size == 0); | ||||
|     LFS2_ASSERT(size % cfg->prog_size == 0); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
| 
 | ||||
|     // check that data was erased? only needed for testing
 | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
|         for (lfs_off_t i = 0; i < size; i++) { | ||||
|             LFS_ASSERT(bd->buffer[block*cfg->block_size + off + i] == | ||||
|         for (lfs2_off_t i = 0; i < size; i++) { | ||||
|             LFS2_ASSERT(bd->buffer[block*cfg->block_size + off + i] == | ||||
|                     bd->cfg->erase_value); | ||||
|         } | ||||
|     } | ||||
| @@ -110,16 +112,16 @@ int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|     // program data
 | ||||
|     memcpy(&bd->buffer[block*cfg->block_size + off], buffer, size); | ||||
| 
 | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_prog -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||
|     lfs_rambd_t *bd = cfg->context; | ||||
| int lfs2_rambd_erase(const struct lfs2_config *cfg, lfs2_block_t block) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||
|     lfs2_rambd_t *bd = cfg->context; | ||||
| 
 | ||||
|     // check if erase is valid
 | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
| 
 | ||||
|     // erase, only needed for testing
 | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
| @@ -127,14 +129,14 @@ int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|                 bd->cfg->erase_value, cfg->block_size); | ||||
|     } | ||||
| 
 | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_erase -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int lfs_rambd_sync(const struct lfs_config *cfg) { | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg); | ||||
| int lfs2_rambd_sync(const struct lfs2_config *cfg) { | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_sync(%p)", (void*)cfg); | ||||
|     // sync does nothing because we aren't backed by anything real
 | ||||
|     (void)cfg; | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0); | ||||
|     LFS2_RAMBD_TRACE("lfs2_rambd_sync -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										75
									
								
								bd/lfs2_rambd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								bd/lfs2_rambd.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
|  * Block device emulated in RAM | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS2_RAMBD_H | ||||
| #define LFS2_RAMBD_H | ||||
|  | ||||
| #include "lfs2.h" | ||||
| #include "lfs2_util.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Block device specific tracing | ||||
| #ifdef LFS2_RAMBD_YES_TRACE | ||||
| #define LFS2_RAMBD_TRACE(...) LFS2_TRACE(__VA_ARGS__) | ||||
| #else | ||||
| #define LFS2_RAMBD_TRACE(...) | ||||
| #endif | ||||
|  | ||||
| // rambd config (optional) | ||||
| struct lfs2_rambd_config { | ||||
|     // 8-bit erase value to simulate erasing with. -1 indicates no erase | ||||
|     // occurs, which is still a valid block device | ||||
|     int32_t erase_value; | ||||
|  | ||||
|     // Optional statically allocated buffer for the block device. | ||||
|     void *buffer; | ||||
| }; | ||||
|  | ||||
| // rambd state | ||||
| typedef struct lfs2_rambd { | ||||
|     uint8_t *buffer; | ||||
|     const struct lfs2_rambd_config *cfg; | ||||
| } lfs2_rambd_t; | ||||
|  | ||||
|  | ||||
| // Create a RAM block device using the geometry in lfs2_config | ||||
| int lfs2_rambd_create(const struct lfs2_config *cfg); | ||||
| int lfs2_rambd_createcfg(const struct lfs2_config *cfg, | ||||
|         const struct lfs2_rambd_config *bdcfg); | ||||
|  | ||||
| // Clean up memory associated with block device | ||||
| int lfs2_rambd_destroy(const struct lfs2_config *cfg); | ||||
|  | ||||
| // Read a block | ||||
| int lfs2_rambd_read(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size); | ||||
|  | ||||
| // Program a block | ||||
| // | ||||
| // The block must have previously been erased. | ||||
| int lfs2_rambd_prog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size); | ||||
|  | ||||
| // Erase a block | ||||
| // | ||||
| // A block must be erased before being programmed. The | ||||
| // state of an erased block is undefined. | ||||
| int lfs2_rambd_erase(const struct lfs2_config *cfg, lfs2_block_t block); | ||||
|  | ||||
| // Sync the block device | ||||
| int lfs2_rambd_sync(const struct lfs2_config *cfg); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										302
									
								
								bd/lfs2_testbd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								bd/lfs2_testbd.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,302 @@ | ||||
| /* | ||||
|  * Testing block device, wraps filebd and rambd while providing a bunch | ||||
|  * of hooks for testing littlefs in various conditions. | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "bd/lfs2_testbd.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
|  | ||||
| int lfs2_testbd_createcfg(const struct lfs2_config *cfg, const char *path, | ||||
|         const struct lfs2_testbd_config *bdcfg) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_createcfg(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
|                 "\"%s\", " | ||||
|                 "%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", " | ||||
|                 ".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", " | ||||
|                 ".buffer=%p, .wear_buffer=%p})", | ||||
|             (void*)cfg, cfg->context, | ||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             path, (void*)bdcfg, bdcfg->erase_value, bdcfg->erase_cycles, | ||||
|             bdcfg->badblock_behavior, bdcfg->power_cycles, | ||||
|             bdcfg->buffer, bdcfg->wear_buffer); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|     bd->cfg = bdcfg; | ||||
|  | ||||
|     // setup testing things | ||||
|     bd->persist = path; | ||||
|     bd->power_cycles = bd->cfg->power_cycles; | ||||
|  | ||||
|     if (bd->cfg->erase_cycles) { | ||||
|         if (bd->cfg->wear_buffer) { | ||||
|             bd->wear = bd->cfg->wear_buffer; | ||||
|         } else { | ||||
|             bd->wear = lfs2_malloc(sizeof(lfs2_testbd_wear_t)*cfg->block_count); | ||||
|             if (!bd->wear) { | ||||
|                 LFS2_TESTBD_TRACE("lfs2_testbd_createcfg -> %d", LFS2_ERR_NOMEM); | ||||
|                 return LFS2_ERR_NOMEM; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         memset(bd->wear, 0, sizeof(lfs2_testbd_wear_t) * cfg->block_count); | ||||
|     } | ||||
|  | ||||
|     // create underlying block device | ||||
|     if (bd->persist) { | ||||
|         bd->u.file.cfg = (struct lfs2_filebd_config){ | ||||
|             .erase_value = bd->cfg->erase_value, | ||||
|         }; | ||||
|         int err = lfs2_filebd_createcfg(cfg, path, &bd->u.file.cfg); | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_createcfg -> %d", err); | ||||
|         return err; | ||||
|     } else { | ||||
|         bd->u.ram.cfg = (struct lfs2_rambd_config){ | ||||
|             .erase_value = bd->cfg->erase_value, | ||||
|             .buffer = bd->cfg->buffer, | ||||
|         }; | ||||
|         int err = lfs2_rambd_createcfg(cfg, &bd->u.ram.cfg); | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_createcfg -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| } | ||||
|  | ||||
| int lfs2_testbd_create(const struct lfs2_config *cfg, const char *path) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_create(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
|                 "\"%s\")", | ||||
|             (void*)cfg, cfg->context, | ||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             path); | ||||
|     static const struct lfs2_testbd_config defaults = {.erase_value=-1}; | ||||
|     int err = lfs2_testbd_createcfg(cfg, path, &defaults); | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_create -> %d", err); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int lfs2_testbd_destroy(const struct lfs2_config *cfg) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_destroy(%p)", (void*)cfg); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|     if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { | ||||
|         lfs2_free(bd->wear); | ||||
|     } | ||||
|  | ||||
|     if (bd->persist) { | ||||
|         int err = lfs2_filebd_destroy(cfg); | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_destroy -> %d", err); | ||||
|         return err; | ||||
|     } else { | ||||
|         int err = lfs2_rambd_destroy(cfg); | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_destroy -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Internal mapping to block devices /// | ||||
| static int lfs2_testbd_rawread(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size) { | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs2_filebd_read(cfg, block, off, buffer, size); | ||||
|     } else { | ||||
|         return lfs2_rambd_read(cfg, block, off, buffer, size); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs2_testbd_rawprog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size) { | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs2_filebd_prog(cfg, block, off, buffer, size); | ||||
|     } else { | ||||
|         return lfs2_rambd_prog(cfg, block, off, buffer, size); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs2_testbd_rawerase(const struct lfs2_config *cfg, | ||||
|         lfs2_block_t block) { | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs2_filebd_erase(cfg, block); | ||||
|     } else { | ||||
|         return lfs2_rambd_erase(cfg, block); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs2_testbd_rawsync(const struct lfs2_config *cfg) { | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs2_filebd_sync(cfg); | ||||
|     } else { | ||||
|         return lfs2_rambd_sync(cfg); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// block device API /// | ||||
| int lfs2_testbd_read(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_read(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if read is valid | ||||
|     LFS2_ASSERT(off  % cfg->read_size == 0); | ||||
|     LFS2_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // block bad? | ||||
|     if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles && | ||||
|             bd->cfg->badblock_behavior == LFS2_TESTBD_BADBLOCK_READERROR) { | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_read -> %d", LFS2_ERR_CORRUPT); | ||||
|         return LFS2_ERR_CORRUPT; | ||||
|     } | ||||
|  | ||||
|     // read | ||||
|     int err = lfs2_testbd_rawread(cfg, block, off, buffer, size); | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_read -> %d", err); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int lfs2_testbd_prog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_prog(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if write is valid | ||||
|     LFS2_ASSERT(off  % cfg->prog_size == 0); | ||||
|     LFS2_ASSERT(size % cfg->prog_size == 0); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // block bad? | ||||
|     if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) { | ||||
|         if (bd->cfg->badblock_behavior == | ||||
|                 LFS2_TESTBD_BADBLOCK_PROGERROR) { | ||||
|             LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", LFS2_ERR_CORRUPT); | ||||
|             return LFS2_ERR_CORRUPT; | ||||
|         } else if (bd->cfg->badblock_behavior == | ||||
|                 LFS2_TESTBD_BADBLOCK_PROGNOOP || | ||||
|                 bd->cfg->badblock_behavior == | ||||
|                 LFS2_TESTBD_BADBLOCK_ERASENOOP) { | ||||
|             LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", 0); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // prog | ||||
|     int err = lfs2_testbd_rawprog(cfg, block, off, buffer, size); | ||||
|     if (err) { | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // lose power? | ||||
|     if (bd->power_cycles > 0) { | ||||
|         bd->power_cycles -= 1; | ||||
|         if (bd->power_cycles == 0) { | ||||
|             // sync to make sure we persist the last changes | ||||
|             LFS2_ASSERT(lfs2_testbd_rawsync(cfg) == 0); | ||||
|             // simulate power loss | ||||
|             exit(33); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs2_testbd_erase(const struct lfs2_config *cfg, lfs2_block_t block) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if erase is valid | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // block bad? | ||||
|     if (bd->cfg->erase_cycles) { | ||||
|         if (bd->wear[block] >= bd->cfg->erase_cycles) { | ||||
|             if (bd->cfg->badblock_behavior == | ||||
|                     LFS2_TESTBD_BADBLOCK_ERASEERROR) { | ||||
|                 LFS2_TESTBD_TRACE("lfs2_testbd_erase -> %d", LFS2_ERR_CORRUPT); | ||||
|                 return LFS2_ERR_CORRUPT; | ||||
|             } else if (bd->cfg->badblock_behavior == | ||||
|                     LFS2_TESTBD_BADBLOCK_ERASENOOP) { | ||||
|                 LFS2_TESTBD_TRACE("lfs2_testbd_erase -> %d", 0); | ||||
|                 return 0; | ||||
|             } | ||||
|         } else { | ||||
|             // mark wear | ||||
|             bd->wear[block] += 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // erase | ||||
|     int err = lfs2_testbd_rawerase(cfg, block); | ||||
|     if (err) { | ||||
|         LFS2_TESTBD_TRACE("lfs2_testbd_erase -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // lose power? | ||||
|     if (bd->power_cycles > 0) { | ||||
|         bd->power_cycles -= 1; | ||||
|         if (bd->power_cycles == 0) { | ||||
|             // sync to make sure we persist the last changes | ||||
|             LFS2_ASSERT(lfs2_testbd_rawsync(cfg) == 0); | ||||
|             // simulate power loss | ||||
|             exit(33); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_prog -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs2_testbd_sync(const struct lfs2_config *cfg) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_sync(%p)", (void*)cfg); | ||||
|     int err = lfs2_testbd_rawsync(cfg); | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_sync -> %d", err); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
|  | ||||
| /// simulated wear operations /// | ||||
| lfs2_testbd_swear_t lfs2_testbd_getwear(const struct lfs2_config *cfg, | ||||
|         lfs2_block_t block) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if block is valid | ||||
|     LFS2_ASSERT(bd->cfg->erase_cycles); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_getwear -> %"PRIu32, bd->wear[block]); | ||||
|     return bd->wear[block]; | ||||
| } | ||||
|  | ||||
| int lfs2_testbd_setwear(const struct lfs2_config *cfg, | ||||
|         lfs2_block_t block, lfs2_testbd_wear_t wear) { | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_setwear(%p, %"PRIu32")", (void*)cfg, block); | ||||
|     lfs2_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if block is valid | ||||
|     LFS2_ASSERT(bd->cfg->erase_cycles); | ||||
|     LFS2_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     bd->wear[block] = wear; | ||||
|  | ||||
|     LFS2_TESTBD_TRACE("lfs2_testbd_setwear -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
| @@ -5,13 +5,13 @@ | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_TESTBD_H | ||||
| #define LFS_TESTBD_H | ||||
| #ifndef LFS2_TESTBD_H | ||||
| #define LFS2_TESTBD_H | ||||
| 
 | ||||
| #include "lfs.h" | ||||
| #include "lfs_util.h" | ||||
| #include "bd/lfs_rambd.h" | ||||
| #include "bd/lfs_filebd.h" | ||||
| #include "lfs2.h" | ||||
| #include "lfs2_util.h" | ||||
| #include "bd/lfs2_rambd.h" | ||||
| #include "bd/lfs2_filebd.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| @@ -20,10 +20,10 @@ extern "C" | ||||
| 
 | ||||
| 
 | ||||
| // Block device specific tracing
 | ||||
| #ifdef LFS_TESTBD_YES_TRACE | ||||
| #define LFS_TESTBD_TRACE(...) LFS_TRACE(__VA_ARGS__) | ||||
| #ifdef LFS2_TESTBD_YES_TRACE | ||||
| #define LFS2_TESTBD_TRACE(...) LFS2_TRACE(__VA_ARGS__) | ||||
| #else | ||||
| #define LFS_TESTBD_TRACE(...) | ||||
| #define LFS2_TESTBD_TRACE(...) | ||||
| #endif | ||||
| 
 | ||||
| // Mode determining how "bad blocks" behave during testing. This simulates
 | ||||
| @@ -32,20 +32,20 @@ extern "C" | ||||
| //
 | ||||
| // Not that read-noop is not allowed. Read _must_ return a consistent (but
 | ||||
| // may be arbitrary) value on every read.
 | ||||
| enum lfs_testbd_badblock_behavior { | ||||
|     LFS_TESTBD_BADBLOCK_PROGERROR, | ||||
|     LFS_TESTBD_BADBLOCK_ERASEERROR, | ||||
|     LFS_TESTBD_BADBLOCK_READERROR, | ||||
|     LFS_TESTBD_BADBLOCK_PROGNOOP, | ||||
|     LFS_TESTBD_BADBLOCK_ERASENOOP, | ||||
| enum lfs2_testbd_badblock_behavior { | ||||
|     LFS2_TESTBD_BADBLOCK_PROGERROR, | ||||
|     LFS2_TESTBD_BADBLOCK_ERASEERROR, | ||||
|     LFS2_TESTBD_BADBLOCK_READERROR, | ||||
|     LFS2_TESTBD_BADBLOCK_PROGNOOP, | ||||
|     LFS2_TESTBD_BADBLOCK_ERASENOOP, | ||||
| }; | ||||
| 
 | ||||
| // Type for measuring wear
 | ||||
| typedef uint32_t lfs_testbd_wear_t; | ||||
| typedef int32_t  lfs_testbd_swear_t; | ||||
| typedef uint32_t lfs2_testbd_wear_t; | ||||
| typedef int32_t  lfs2_testbd_swear_t; | ||||
| 
 | ||||
| // testbd config, this is required for testing
 | ||||
| struct lfs_testbd_config { | ||||
| struct lfs2_testbd_config { | ||||
|     // 8-bit erase value to use for simulating erases. -1 does not simulate
 | ||||
|     // erases, which can speed up testing by avoiding all the extra block-device
 | ||||
|     // operations to store the erase value.
 | ||||
| @@ -70,68 +70,68 @@ struct lfs_testbd_config { | ||||
| }; | ||||
| 
 | ||||
| // testbd state
 | ||||
| typedef struct lfs_testbd { | ||||
| typedef struct lfs2_testbd { | ||||
|     union { | ||||
|         struct { | ||||
|             lfs_filebd_t bd; | ||||
|             struct lfs_filebd_config cfg; | ||||
|             lfs2_filebd_t bd; | ||||
|             struct lfs2_filebd_config cfg; | ||||
|         } file; | ||||
|         struct { | ||||
|             lfs_rambd_t bd; | ||||
|             struct lfs_rambd_config cfg; | ||||
|             lfs2_rambd_t bd; | ||||
|             struct lfs2_rambd_config cfg; | ||||
|         } ram; | ||||
|     } u; | ||||
| 
 | ||||
|     bool persist; | ||||
|     uint32_t power_cycles; | ||||
|     lfs_testbd_wear_t *wear; | ||||
|     lfs2_testbd_wear_t *wear; | ||||
| 
 | ||||
|     const struct lfs_testbd_config *cfg; | ||||
| } lfs_testbd_t; | ||||
|     const struct lfs2_testbd_config *cfg; | ||||
| } lfs2_testbd_t; | ||||
| 
 | ||||
| 
 | ||||
| /// Block device API ///
 | ||||
| 
 | ||||
| // Create a test block device using the geometry in lfs_config
 | ||||
| // Create a test block device using the geometry in lfs2_config
 | ||||
| //
 | ||||
| // Note that filebd is used if a path is provided, if path is NULL
 | ||||
| // testbd will use rambd which can be much faster.
 | ||||
| int lfs_testbd_create(const struct lfs_config *cfg, const char *path); | ||||
| int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | ||||
|         const struct lfs_testbd_config *bdcfg); | ||||
| int lfs2_testbd_create(const struct lfs2_config *cfg, const char *path); | ||||
| int lfs2_testbd_createcfg(const struct lfs2_config *cfg, const char *path, | ||||
|         const struct lfs2_testbd_config *bdcfg); | ||||
| 
 | ||||
| // Clean up memory associated with block device
 | ||||
| int lfs_testbd_destroy(const struct lfs_config *cfg); | ||||
| int lfs2_testbd_destroy(const struct lfs2_config *cfg); | ||||
| 
 | ||||
| // Read a block
 | ||||
| int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size); | ||||
| int lfs2_testbd_read(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, void *buffer, lfs2_size_t size); | ||||
| 
 | ||||
| // Program a block
 | ||||
| //
 | ||||
| // The block must have previously been erased.
 | ||||
| int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||
| int lfs2_testbd_prog(const struct lfs2_config *cfg, lfs2_block_t block, | ||||
|         lfs2_off_t off, const void *buffer, lfs2_size_t size); | ||||
| 
 | ||||
| // Erase a block
 | ||||
| //
 | ||||
| // A block must be erased before being programmed. The
 | ||||
| // state of an erased block is undefined.
 | ||||
| int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block); | ||||
| int lfs2_testbd_erase(const struct lfs2_config *cfg, lfs2_block_t block); | ||||
| 
 | ||||
| // Sync the block device
 | ||||
| int lfs_testbd_sync(const struct lfs_config *cfg); | ||||
| int lfs2_testbd_sync(const struct lfs2_config *cfg); | ||||
| 
 | ||||
| 
 | ||||
| /// Additional extended API for driving test features ///
 | ||||
| 
 | ||||
| // Get simulated wear on a given block
 | ||||
| lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, | ||||
|         lfs_block_t block); | ||||
| lfs2_testbd_swear_t lfs2_testbd_getwear(const struct lfs2_config *cfg, | ||||
|         lfs2_block_t block); | ||||
| 
 | ||||
| // Manually set simulated wear on a given block
 | ||||
| int lfs_testbd_setwear(const struct lfs_config *cfg, | ||||
|         lfs_block_t block, lfs_testbd_wear_t wear); | ||||
| int lfs2_testbd_setwear(const struct lfs2_config *cfg, | ||||
|         lfs2_block_t block, lfs2_testbd_wear_t wear); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| @@ -1,73 +0,0 @@ | ||||
| /* | ||||
|  * Block device emulated in a file | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_FILEBD_H | ||||
| #define LFS_FILEBD_H | ||||
|  | ||||
| #include "lfs.h" | ||||
| #include "lfs_util.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Block device specific tracing | ||||
| #ifdef LFS_FILEBD_YES_TRACE | ||||
| #define LFS_FILEBD_TRACE(...) LFS_TRACE(__VA_ARGS__) | ||||
| #else | ||||
| #define LFS_FILEBD_TRACE(...) | ||||
| #endif | ||||
|  | ||||
| // filebd config (optional) | ||||
| struct lfs_filebd_config { | ||||
|     // 8-bit erase value to use for simulating erases. -1 does not simulate | ||||
|     // erases, which can speed up testing by avoiding all the extra block-device | ||||
|     // operations to store the erase value. | ||||
|     int32_t erase_value; | ||||
| }; | ||||
|  | ||||
| // filebd state | ||||
| typedef struct lfs_filebd { | ||||
|     int fd; | ||||
|     const struct lfs_filebd_config *cfg; | ||||
| } lfs_filebd_t; | ||||
|  | ||||
|  | ||||
| // Create a file block device using the geometry in lfs_config | ||||
| int lfs_filebd_create(const struct lfs_config *cfg, const char *path); | ||||
| int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path, | ||||
|         const struct lfs_filebd_config *bdcfg); | ||||
|  | ||||
| // Clean up memory associated with block device | ||||
| int lfs_filebd_destroy(const struct lfs_config *cfg); | ||||
|  | ||||
| // Read a block | ||||
| int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size); | ||||
|  | ||||
| // Program a block | ||||
| // | ||||
| // The block must have previously been erased. | ||||
| int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||
|  | ||||
| // Erase a block | ||||
| // | ||||
| // A block must be erased before being programmed. The | ||||
| // state of an erased block is undefined. | ||||
| int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block); | ||||
|  | ||||
| // Sync the block device | ||||
| int lfs_filebd_sync(const struct lfs_config *cfg); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,75 +0,0 @@ | ||||
| /* | ||||
|  * Block device emulated in RAM | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_RAMBD_H | ||||
| #define LFS_RAMBD_H | ||||
|  | ||||
| #include "lfs.h" | ||||
| #include "lfs_util.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Block device specific tracing | ||||
| #ifdef LFS_RAMBD_YES_TRACE | ||||
| #define LFS_RAMBD_TRACE(...) LFS_TRACE(__VA_ARGS__) | ||||
| #else | ||||
| #define LFS_RAMBD_TRACE(...) | ||||
| #endif | ||||
|  | ||||
| // rambd config (optional) | ||||
| struct lfs_rambd_config { | ||||
|     // 8-bit erase value to simulate erasing with. -1 indicates no erase | ||||
|     // occurs, which is still a valid block device | ||||
|     int32_t erase_value; | ||||
|  | ||||
|     // Optional statically allocated buffer for the block device. | ||||
|     void *buffer; | ||||
| }; | ||||
|  | ||||
| // rambd state | ||||
| typedef struct lfs_rambd { | ||||
|     uint8_t *buffer; | ||||
|     const struct lfs_rambd_config *cfg; | ||||
| } lfs_rambd_t; | ||||
|  | ||||
|  | ||||
| // Create a RAM block device using the geometry in lfs_config | ||||
| int lfs_rambd_create(const struct lfs_config *cfg); | ||||
| int lfs_rambd_createcfg(const struct lfs_config *cfg, | ||||
|         const struct lfs_rambd_config *bdcfg); | ||||
|  | ||||
| // Clean up memory associated with block device | ||||
| int lfs_rambd_destroy(const struct lfs_config *cfg); | ||||
|  | ||||
| // Read a block | ||||
| int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size); | ||||
|  | ||||
| // Program a block | ||||
| // | ||||
| // The block must have previously been erased. | ||||
| int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size); | ||||
|  | ||||
| // Erase a block | ||||
| // | ||||
| // A block must be erased before being programmed. The | ||||
| // state of an erased block is undefined. | ||||
| int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block); | ||||
|  | ||||
| // Sync the block device | ||||
| int lfs_rambd_sync(const struct lfs_config *cfg); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										302
									
								
								bd/lfs_testbd.c
									
									
									
									
									
								
							
							
						
						
									
										302
									
								
								bd/lfs_testbd.c
									
									
									
									
									
								
							| @@ -1,302 +0,0 @@ | ||||
| /* | ||||
|  * Testing block device, wraps filebd and rambd while providing a bunch | ||||
|  * of hooks for testing littlefs in various conditions. | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "bd/lfs_testbd.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
|  | ||||
| int lfs_testbd_createcfg(const struct lfs_config *cfg, const char *path, | ||||
|         const struct lfs_testbd_config *bdcfg) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_createcfg(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
|                 "\"%s\", " | ||||
|                 "%p {.erase_value=%"PRId32", .erase_cycles=%"PRIu32", " | ||||
|                 ".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", " | ||||
|                 ".buffer=%p, .wear_buffer=%p})", | ||||
|             (void*)cfg, cfg->context, | ||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             path, (void*)bdcfg, bdcfg->erase_value, bdcfg->erase_cycles, | ||||
|             bdcfg->badblock_behavior, bdcfg->power_cycles, | ||||
|             bdcfg->buffer, bdcfg->wear_buffer); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|     bd->cfg = bdcfg; | ||||
|  | ||||
|     // setup testing things | ||||
|     bd->persist = path; | ||||
|     bd->power_cycles = bd->cfg->power_cycles; | ||||
|  | ||||
|     if (bd->cfg->erase_cycles) { | ||||
|         if (bd->cfg->wear_buffer) { | ||||
|             bd->wear = bd->cfg->wear_buffer; | ||||
|         } else { | ||||
|             bd->wear = lfs_malloc(sizeof(lfs_testbd_wear_t)*cfg->block_count); | ||||
|             if (!bd->wear) { | ||||
|                 LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", LFS_ERR_NOMEM); | ||||
|                 return LFS_ERR_NOMEM; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         memset(bd->wear, 0, sizeof(lfs_testbd_wear_t) * cfg->block_count); | ||||
|     } | ||||
|  | ||||
|     // create underlying block device | ||||
|     if (bd->persist) { | ||||
|         bd->u.file.cfg = (struct lfs_filebd_config){ | ||||
|             .erase_value = bd->cfg->erase_value, | ||||
|         }; | ||||
|         int err = lfs_filebd_createcfg(cfg, path, &bd->u.file.cfg); | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); | ||||
|         return err; | ||||
|     } else { | ||||
|         bd->u.ram.cfg = (struct lfs_rambd_config){ | ||||
|             .erase_value = bd->cfg->erase_value, | ||||
|             .buffer = bd->cfg->buffer, | ||||
|         }; | ||||
|         int err = lfs_rambd_createcfg(cfg, &bd->u.ram.cfg); | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_createcfg -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| } | ||||
|  | ||||
| int lfs_testbd_create(const struct lfs_config *cfg, const char *path) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_create(%p {.context=%p, " | ||||
|                 ".read=%p, .prog=%p, .erase=%p, .sync=%p, " | ||||
|                 ".read_size=%"PRIu32", .prog_size=%"PRIu32", " | ||||
|                 ".block_size=%"PRIu32", .block_count=%"PRIu32"}, " | ||||
|                 "\"%s\")", | ||||
|             (void*)cfg, cfg->context, | ||||
|             (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, | ||||
|             (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, | ||||
|             cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, | ||||
|             path); | ||||
|     static const struct lfs_testbd_config defaults = {.erase_value=-1}; | ||||
|     int err = lfs_testbd_createcfg(cfg, path, &defaults); | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_create -> %d", err); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int lfs_testbd_destroy(const struct lfs_config *cfg) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_destroy(%p)", (void*)cfg); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|     if (bd->cfg->erase_cycles && !bd->cfg->wear_buffer) { | ||||
|         lfs_free(bd->wear); | ||||
|     } | ||||
|  | ||||
|     if (bd->persist) { | ||||
|         int err = lfs_filebd_destroy(cfg); | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); | ||||
|         return err; | ||||
|     } else { | ||||
|         int err = lfs_rambd_destroy(cfg); | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_destroy -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Internal mapping to block devices /// | ||||
| static int lfs_testbd_rawread(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs_filebd_read(cfg, block, off, buffer, size); | ||||
|     } else { | ||||
|         return lfs_rambd_read(cfg, block, off, buffer, size); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs_testbd_rawprog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs_filebd_prog(cfg, block, off, buffer, size); | ||||
|     } else { | ||||
|         return lfs_rambd_prog(cfg, block, off, buffer, size); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs_testbd_rawerase(const struct lfs_config *cfg, | ||||
|         lfs_block_t block) { | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs_filebd_erase(cfg, block); | ||||
|     } else { | ||||
|         return lfs_rambd_erase(cfg, block); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs_testbd_rawsync(const struct lfs_config *cfg) { | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|     if (bd->persist) { | ||||
|         return lfs_filebd_sync(cfg); | ||||
|     } else { | ||||
|         return lfs_rambd_sync(cfg); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// block device API /// | ||||
| int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_read(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if read is valid | ||||
|     LFS_ASSERT(off  % cfg->read_size == 0); | ||||
|     LFS_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // block bad? | ||||
|     if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles && | ||||
|             bd->cfg->badblock_behavior == LFS_TESTBD_BADBLOCK_READERROR) { | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_read -> %d", LFS_ERR_CORRUPT); | ||||
|         return LFS_ERR_CORRUPT; | ||||
|     } | ||||
|  | ||||
|     // read | ||||
|     int err = lfs_testbd_rawread(cfg, block, off, buffer, size); | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_read -> %d", err); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_prog(%p, " | ||||
|                 "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")", | ||||
|             (void*)cfg, block, off, buffer, size); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if write is valid | ||||
|     LFS_ASSERT(off  % cfg->prog_size == 0); | ||||
|     LFS_ASSERT(size % cfg->prog_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // block bad? | ||||
|     if (bd->cfg->erase_cycles && bd->wear[block] >= bd->cfg->erase_cycles) { | ||||
|         if (bd->cfg->badblock_behavior == | ||||
|                 LFS_TESTBD_BADBLOCK_PROGERROR) { | ||||
|             LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", LFS_ERR_CORRUPT); | ||||
|             return LFS_ERR_CORRUPT; | ||||
|         } else if (bd->cfg->badblock_behavior == | ||||
|                 LFS_TESTBD_BADBLOCK_PROGNOOP || | ||||
|                 bd->cfg->badblock_behavior == | ||||
|                 LFS_TESTBD_BADBLOCK_ERASENOOP) { | ||||
|             LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // prog | ||||
|     int err = lfs_testbd_rawprog(cfg, block, off, buffer, size); | ||||
|     if (err) { | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // lose power? | ||||
|     if (bd->power_cycles > 0) { | ||||
|         bd->power_cycles -= 1; | ||||
|         if (bd->power_cycles == 0) { | ||||
|             // sync to make sure we persist the last changes | ||||
|             LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); | ||||
|             // simulate power loss | ||||
|             exit(33); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_erase(%p, 0x%"PRIx32")", (void*)cfg, block); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if erase is valid | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // block bad? | ||||
|     if (bd->cfg->erase_cycles) { | ||||
|         if (bd->wear[block] >= bd->cfg->erase_cycles) { | ||||
|             if (bd->cfg->badblock_behavior == | ||||
|                     LFS_TESTBD_BADBLOCK_ERASEERROR) { | ||||
|                 LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", LFS_ERR_CORRUPT); | ||||
|                 return LFS_ERR_CORRUPT; | ||||
|             } else if (bd->cfg->badblock_behavior == | ||||
|                     LFS_TESTBD_BADBLOCK_ERASENOOP) { | ||||
|                 LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", 0); | ||||
|                 return 0; | ||||
|             } | ||||
|         } else { | ||||
|             // mark wear | ||||
|             bd->wear[block] += 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // erase | ||||
|     int err = lfs_testbd_rawerase(cfg, block); | ||||
|     if (err) { | ||||
|         LFS_TESTBD_TRACE("lfs_testbd_erase -> %d", err); | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // lose power? | ||||
|     if (bd->power_cycles > 0) { | ||||
|         bd->power_cycles -= 1; | ||||
|         if (bd->power_cycles == 0) { | ||||
|             // sync to make sure we persist the last changes | ||||
|             LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); | ||||
|             // simulate power loss | ||||
|             exit(33); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_prog -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_testbd_sync(const struct lfs_config *cfg) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_sync(%p)", (void*)cfg); | ||||
|     int err = lfs_testbd_rawsync(cfg); | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_sync -> %d", err); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
|  | ||||
| /// simulated wear operations /// | ||||
| lfs_testbd_swear_t lfs_testbd_getwear(const struct lfs_config *cfg, | ||||
|         lfs_block_t block) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_getwear(%p, %"PRIu32")", (void*)cfg, block); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if block is valid | ||||
|     LFS_ASSERT(bd->cfg->erase_cycles); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_getwear -> %"PRIu32, bd->wear[block]); | ||||
|     return bd->wear[block]; | ||||
| } | ||||
|  | ||||
| int lfs_testbd_setwear(const struct lfs_config *cfg, | ||||
|         lfs_block_t block, lfs_testbd_wear_t wear) { | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_setwear(%p, %"PRIu32")", (void*)cfg, block); | ||||
|     lfs_testbd_t *bd = cfg->context; | ||||
|  | ||||
|     // check if block is valid | ||||
|     LFS_ASSERT(bd->cfg->erase_cycles); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     bd->wear[block] = wear; | ||||
|  | ||||
|     LFS_TESTBD_TRACE("lfs_testbd_setwear -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										518
									
								
								lfs.h → lfs2.h
									
									
									
									
									
								
							
							
						
						
									
										518
									
								
								lfs.h → lfs2.h
									
									
									
									
									
								
							| @@ -4,12 +4,12 @@ | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_H | ||||
| #define LFS_H | ||||
| #ifndef LFS2_H | ||||
| #define LFS2_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "lfs_util.h" | ||||
| #include "lfs2_util.h" | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| @@ -22,190 +22,190 @@ extern "C" | ||||
| // Software library version
 | ||||
| // Major (top-nibble), incremented on backwards incompatible changes
 | ||||
| // Minor (bottom-nibble), incremented on feature additions
 | ||||
| #define LFS_VERSION 0x00020004 | ||||
| #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) | ||||
| #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >>  0)) | ||||
| #define LFS2_VERSION 0x00020004 | ||||
| #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 LFS_DISK_VERSION 0x00020000 | ||||
| #define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) | ||||
| #define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >>  0)) | ||||
| #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 lfs_size_t; | ||||
| typedef uint32_t lfs_off_t; | ||||
| typedef uint32_t lfs2_size_t; | ||||
| typedef uint32_t lfs2_off_t; | ||||
| 
 | ||||
| typedef int32_t  lfs_ssize_t; | ||||
| typedef int32_t  lfs_soff_t; | ||||
| typedef int32_t  lfs2_ssize_t; | ||||
| typedef int32_t  lfs2_soff_t; | ||||
| 
 | ||||
| typedef uint32_t lfs_block_t; | ||||
| typedef uint32_t lfs2_block_t; | ||||
| 
 | ||||
| // Maximum name size in bytes, may be redefined to reduce the size of the
 | ||||
| // info struct. Limited to <= 1022. Stored in superblock and must be
 | ||||
| // respected by other littlefs drivers.
 | ||||
| #ifndef LFS_NAME_MAX | ||||
| #define LFS_NAME_MAX 255 | ||||
| #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 lfs_file_seek, lfs_file_size, and lfs_file_tell will return
 | ||||
| // functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return
 | ||||
| // incorrect values due to using signed integers. Stored in superblock and
 | ||||
| // must be respected by other littlefs drivers.
 | ||||
| #ifndef LFS_FILE_MAX | ||||
| #define LFS_FILE_MAX 2147483647 | ||||
| #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 LFS_ATTR_MAX. Limited to <= 1022.
 | ||||
| #ifndef LFS_ATTR_MAX | ||||
| #define LFS_ATTR_MAX 1022 | ||||
| // 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 lfs_error { | ||||
|     LFS_ERR_OK          = 0,    // No error
 | ||||
|     LFS_ERR_IO          = -5,   // Error during device operation
 | ||||
|     LFS_ERR_CORRUPT     = -84,  // Corrupted
 | ||||
|     LFS_ERR_NOENT       = -2,   // No directory entry
 | ||||
|     LFS_ERR_EXIST       = -17,  // Entry already exists
 | ||||
|     LFS_ERR_NOTDIR      = -20,  // Entry is not a dir
 | ||||
|     LFS_ERR_ISDIR       = -21,  // Entry is a dir
 | ||||
|     LFS_ERR_NOTEMPTY    = -39,  // Dir is not empty
 | ||||
|     LFS_ERR_BADF        = -9,   // Bad file number
 | ||||
|     LFS_ERR_FBIG        = -27,  // File too large
 | ||||
|     LFS_ERR_INVAL       = -22,  // Invalid parameter
 | ||||
|     LFS_ERR_NOSPC       = -28,  // No space left on device
 | ||||
|     LFS_ERR_NOMEM       = -12,  // No more memory available
 | ||||
|     LFS_ERR_NOATTR      = -61,  // No data/attr available
 | ||||
|     LFS_ERR_NAMETOOLONG = -36,  // File name too long
 | ||||
| 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 lfs_type { | ||||
| enum lfs2_type { | ||||
|     // file types
 | ||||
|     LFS_TYPE_REG            = 0x001, | ||||
|     LFS_TYPE_DIR            = 0x002, | ||||
|     LFS2_TYPE_REG            = 0x001, | ||||
|     LFS2_TYPE_DIR            = 0x002, | ||||
| 
 | ||||
|     // internally used types
 | ||||
|     LFS_TYPE_SPLICE         = 0x400, | ||||
|     LFS_TYPE_NAME           = 0x000, | ||||
|     LFS_TYPE_STRUCT         = 0x200, | ||||
|     LFS_TYPE_USERATTR       = 0x300, | ||||
|     LFS_TYPE_FROM           = 0x100, | ||||
|     LFS_TYPE_TAIL           = 0x600, | ||||
|     LFS_TYPE_GLOBALS        = 0x700, | ||||
|     LFS_TYPE_CRC            = 0x500, | ||||
|     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
 | ||||
|     LFS_TYPE_CREATE         = 0x401, | ||||
|     LFS_TYPE_DELETE         = 0x4ff, | ||||
|     LFS_TYPE_SUPERBLOCK     = 0x0ff, | ||||
|     LFS_TYPE_DIRSTRUCT      = 0x200, | ||||
|     LFS_TYPE_CTZSTRUCT      = 0x202, | ||||
|     LFS_TYPE_INLINESTRUCT   = 0x201, | ||||
|     LFS_TYPE_SOFTTAIL       = 0x600, | ||||
|     LFS_TYPE_HARDTAIL       = 0x601, | ||||
|     LFS_TYPE_MOVESTATE      = 0x7ff, | ||||
|     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
 | ||||
|     LFS_FROM_NOOP           = 0x000, | ||||
|     LFS_FROM_MOVE           = 0x101, | ||||
|     LFS_FROM_USERATTRS      = 0x102, | ||||
|     LFS2_FROM_NOOP           = 0x000, | ||||
|     LFS2_FROM_MOVE           = 0x101, | ||||
|     LFS2_FROM_USERATTRS      = 0x102, | ||||
| }; | ||||
| 
 | ||||
| // File open flags
 | ||||
| enum lfs_open_flags { | ||||
| enum lfs2_open_flags { | ||||
|     // open flags
 | ||||
|     LFS_O_RDONLY = 1,         // Open a file as read only
 | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_O_WRONLY = 2,         // Open a file as write only
 | ||||
|     LFS_O_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
 | ||||
|     LFS2_O_RDONLY = 1,         // Open a file as read only
 | ||||
| #ifndef LFS2_READONLY | ||||
|     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
 | ||||
| #endif | ||||
| 
 | ||||
|     // internally used flags
 | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_F_DIRTY   = 0x010000, // File does not match storage
 | ||||
|     LFS_F_WRITING = 0x020000, // File has been written since last flush
 | ||||
| #ifndef LFS2_READONLY | ||||
|     LFS2_F_DIRTY   = 0x010000, // File does not match storage
 | ||||
|     LFS2_F_WRITING = 0x020000, // File has been written since last flush
 | ||||
| #endif | ||||
|     LFS_F_READING = 0x040000, // File has been read since last flush
 | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_F_ERRED   = 0x080000, // An error occurred during write
 | ||||
|     LFS2_F_READING = 0x040000, // File has been read since last flush
 | ||||
| #ifndef LFS2_READONLY | ||||
|     LFS2_F_ERRED   = 0x080000, // An error occurred during write
 | ||||
| #endif | ||||
|     LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry
 | ||||
|     LFS2_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
 | ||||
| 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 lfs_config { | ||||
| 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
 | ||||
|     // Read a region in a block. Negative error codes are propagated
 | ||||
|     // to the user.
 | ||||
|     int (*read)(const struct lfs_config *c, lfs_block_t block, | ||||
|             lfs_off_t off, void *buffer, lfs_size_t size); | ||||
|     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 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); | ||||
|     // been erased. Negative error codes are propagated 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 LFS_ERR_CORRUPT if the block should be considered bad.
 | ||||
|     int (*erase)(const struct lfs_config *c, lfs_block_t block); | ||||
|     // are propagated 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 lfs_config *c); | ||||
|     // are propagated to the user.
 | ||||
|     int (*sync)(const struct lfs2_config *c); | ||||
| 
 | ||||
| #ifdef LFS_THREADSAFE | ||||
| #ifdef LFS2_THREADSAFE | ||||
|     // Lock the underlying block device. Negative error codes
 | ||||
|     // are propogated to the user.
 | ||||
|     int (*lock)(const struct lfs_config *c); | ||||
|     // are propagated to the user.
 | ||||
|     int (*lock)(const struct lfs2_config *c); | ||||
| 
 | ||||
|     // Unlock the underlying block device. Negative error codes
 | ||||
|     // are propogated to the user.
 | ||||
|     int (*unlock)(const struct lfs_config *c); | ||||
|     // are propagated to the user.
 | ||||
|     int (*unlock)(const struct lfs2_config *c); | ||||
| #endif | ||||
| 
 | ||||
|     // Minimum size of a block read. All read operations will be a
 | ||||
|     // Minimum size of a block read in bytes. All read operations will be a
 | ||||
|     // multiple of this value.
 | ||||
|     lfs_size_t read_size; | ||||
|     lfs2_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; | ||||
|     // Minimum size of a block program in bytes. 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.
 | ||||
|     lfs_size_t block_size; | ||||
|     // Size of an erasable block in bytes. This does not impact ram consumption
 | ||||
|     // and may be larger than the physical erase size. However, non-inlined
 | ||||
|     // 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.
 | ||||
|     lfs_size_t block_count; | ||||
|     lfs2_size_t block_count; | ||||
| 
 | ||||
|     // Number of erase cycles before littlefs evicts metadata logs and moves
 | ||||
|     // the metadata to another block. Suggested values are in the
 | ||||
| @@ -215,73 +215,73 @@ struct lfs_config { | ||||
|     // Set to -1 to disable block-level wear-leveling.
 | ||||
|     int32_t block_cycles; | ||||
| 
 | ||||
|     // Size of block caches. Each cache buffers a portion of a block in RAM.
 | ||||
|     // The littlefs needs a read cache, a program cache, and one additional
 | ||||
|     // Size of block caches in bytes. 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.
 | ||||
|     lfs_size_t cache_size; | ||||
|     // 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 8.
 | ||||
|     lfs_size_t lookahead_size; | ||||
|     lfs2_size_t lookahead_size; | ||||
| 
 | ||||
|     // Optional statically allocated read buffer. Must be cache_size.
 | ||||
|     // By default lfs_malloc is used to allocate this buffer.
 | ||||
|     // By default lfs2_malloc is used to allocate this buffer.
 | ||||
|     void *read_buffer; | ||||
| 
 | ||||
|     // Optional statically allocated program buffer. Must be cache_size.
 | ||||
|     // By default lfs_malloc is used to allocate this buffer.
 | ||||
|     // By default lfs2_malloc is used to allocate this buffer.
 | ||||
|     void *prog_buffer; | ||||
| 
 | ||||
|     // Optional statically allocated lookahead buffer. Must be lookahead_size
 | ||||
|     // and aligned to a 32-bit boundary. By default lfs_malloc is used to
 | ||||
|     // and aligned to a 32-bit boundary. By default lfs2_malloc is used to
 | ||||
|     // allocate this buffer.
 | ||||
|     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 LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
 | ||||
|     // the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in
 | ||||
|     // superblock and must be respected by other littlefs drivers.
 | ||||
|     lfs_size_t name_max; | ||||
|     lfs2_size_t name_max; | ||||
| 
 | ||||
|     // Optional upper limit on files in bytes. No downside for larger files
 | ||||
|     // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
 | ||||
|     // but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored
 | ||||
|     // in superblock and must be respected by other littlefs drivers.
 | ||||
|     lfs_size_t file_max; | ||||
|     lfs2_size_t file_max; | ||||
| 
 | ||||
|     // Optional upper limit on custom attributes in bytes. No downside for
 | ||||
|     // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
 | ||||
|     // LFS_ATTR_MAX when zero.
 | ||||
|     lfs_size_t attr_max; | ||||
|     // larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to
 | ||||
|     // LFS2_ATTR_MAX when zero.
 | ||||
|     lfs2_size_t attr_max; | ||||
| 
 | ||||
|     // Optional upper limit on total space given to metadata pairs in bytes. On
 | ||||
|     // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
 | ||||
|     // can help bound the metadata compaction time. Must be <= block_size.
 | ||||
|     // Defaults to block_size when zero.
 | ||||
|     lfs_size_t metadata_max; | ||||
|     lfs2_size_t metadata_max; | ||||
| }; | ||||
| 
 | ||||
| // File info structure
 | ||||
| struct lfs_info { | ||||
|     // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
 | ||||
| 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.
 | ||||
|     lfs_size_t size; | ||||
|     lfs2_size_t size; | ||||
| 
 | ||||
|     // Name of the file stored as a null-terminated string. Limited to
 | ||||
|     // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
 | ||||
|     // reduce RAM. LFS_NAME_MAX is stored in superblock and must be
 | ||||
|     // 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[LFS_NAME_MAX+1]; | ||||
|     char name[LFS2_NAME_MAX+1]; | ||||
| }; | ||||
| 
 | ||||
| // Custom attribute structure, used to describe custom attributes
 | ||||
| // committed atomically during file writes.
 | ||||
| struct lfs_attr { | ||||
| struct lfs2_attr { | ||||
|     // 8-bit type of attribute, provided by user and used to
 | ||||
|     // identify the attribute
 | ||||
|     uint8_t type; | ||||
| @@ -289,14 +289,14 @@ struct lfs_attr { | ||||
|     // Pointer to buffer containing the attribute
 | ||||
|     void *buffer; | ||||
| 
 | ||||
|     // Size of attribute in bytes, limited to LFS_ATTR_MAX
 | ||||
|     lfs_size_t size; | ||||
|     // Size of attribute in bytes, limited to LFS2_ATTR_MAX
 | ||||
|     lfs2_size_t size; | ||||
| }; | ||||
| 
 | ||||
| // Optional configuration provided during lfs_file_opencfg
 | ||||
| struct lfs_file_config { | ||||
| // Optional configuration provided during lfs2_file_opencfg
 | ||||
| struct lfs2_file_config { | ||||
|     // Optional statically allocated file buffer. Must be cache_size.
 | ||||
|     // By default lfs_malloc is used to allocate this buffer.
 | ||||
|     // By default lfs2_malloc is used to allocate this buffer.
 | ||||
|     void *buffer; | ||||
| 
 | ||||
|     // Optional list of custom attributes related to the file. If the file
 | ||||
| @@ -306,122 +306,122 @@ struct lfs_file_config { | ||||
|     // 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
 | ||||
|     // 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 lfs_attr *attrs; | ||||
|     struct lfs2_attr *attrs; | ||||
| 
 | ||||
|     // Number of custom attributes in the list
 | ||||
|     lfs_size_t attr_count; | ||||
|     lfs2_size_t attr_count; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /// internal littlefs data structures ///
 | ||||
| typedef struct lfs_cache { | ||||
|     lfs_block_t block; | ||||
|     lfs_off_t off; | ||||
|     lfs_size_t size; | ||||
| typedef struct lfs2_cache { | ||||
|     lfs2_block_t block; | ||||
|     lfs2_off_t off; | ||||
|     lfs2_size_t size; | ||||
|     uint8_t *buffer; | ||||
| } lfs_cache_t; | ||||
| } lfs2_cache_t; | ||||
| 
 | ||||
| typedef struct lfs_mdir { | ||||
|     lfs_block_t pair[2]; | ||||
| typedef struct lfs2_mdir { | ||||
|     lfs2_block_t pair[2]; | ||||
|     uint32_t rev; | ||||
|     lfs_off_t off; | ||||
|     lfs2_off_t off; | ||||
|     uint32_t etag; | ||||
|     uint16_t count; | ||||
|     bool erased; | ||||
|     bool split; | ||||
|     lfs_block_t tail[2]; | ||||
| } lfs_mdir_t; | ||||
|     lfs2_block_t tail[2]; | ||||
| } lfs2_mdir_t; | ||||
| 
 | ||||
| // littlefs directory type
 | ||||
| typedef struct lfs_dir { | ||||
|     struct lfs_dir *next; | ||||
| typedef struct lfs2_dir { | ||||
|     struct lfs2_dir *next; | ||||
|     uint16_t id; | ||||
|     uint8_t type; | ||||
|     lfs_mdir_t m; | ||||
|     lfs2_mdir_t m; | ||||
| 
 | ||||
|     lfs_off_t pos; | ||||
|     lfs_block_t head[2]; | ||||
| } lfs_dir_t; | ||||
|     lfs2_off_t pos; | ||||
|     lfs2_block_t head[2]; | ||||
| } lfs2_dir_t; | ||||
| 
 | ||||
| // littlefs file type
 | ||||
| typedef struct lfs_file { | ||||
|     struct lfs_file *next; | ||||
| typedef struct lfs2_file { | ||||
|     struct lfs2_file *next; | ||||
|     uint16_t id; | ||||
|     uint8_t type; | ||||
|     lfs_mdir_t m; | ||||
|     lfs2_mdir_t m; | ||||
| 
 | ||||
|     struct lfs_ctz { | ||||
|         lfs_block_t head; | ||||
|         lfs_size_t size; | ||||
|     struct lfs2_ctz { | ||||
|         lfs2_block_t head; | ||||
|         lfs2_size_t size; | ||||
|     } ctz; | ||||
| 
 | ||||
|     uint32_t flags; | ||||
|     lfs_off_t pos; | ||||
|     lfs_block_t block; | ||||
|     lfs_off_t off; | ||||
|     lfs_cache_t cache; | ||||
|     lfs2_off_t pos; | ||||
|     lfs2_block_t block; | ||||
|     lfs2_off_t off; | ||||
|     lfs2_cache_t cache; | ||||
| 
 | ||||
|     const struct lfs_file_config *cfg; | ||||
| } lfs_file_t; | ||||
|     const struct lfs2_file_config *cfg; | ||||
| } lfs2_file_t; | ||||
| 
 | ||||
| typedef struct lfs_superblock { | ||||
| typedef struct lfs2_superblock { | ||||
|     uint32_t version; | ||||
|     lfs_size_t block_size; | ||||
|     lfs_size_t block_count; | ||||
|     lfs_size_t name_max; | ||||
|     lfs_size_t file_max; | ||||
|     lfs_size_t attr_max; | ||||
| } lfs_superblock_t; | ||||
|     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; | ||||
| 
 | ||||
| typedef struct lfs_gstate { | ||||
| typedef struct lfs2_gstate { | ||||
|     uint32_t tag; | ||||
|     lfs_block_t pair[2]; | ||||
| } lfs_gstate_t; | ||||
|     lfs2_block_t pair[2]; | ||||
| } lfs2_gstate_t; | ||||
| 
 | ||||
| // The littlefs filesystem type
 | ||||
| typedef struct lfs { | ||||
|     lfs_cache_t rcache; | ||||
|     lfs_cache_t pcache; | ||||
| typedef struct lfs2 { | ||||
|     lfs2_cache_t rcache; | ||||
|     lfs2_cache_t pcache; | ||||
| 
 | ||||
|     lfs_block_t root[2]; | ||||
|     struct lfs_mlist { | ||||
|         struct lfs_mlist *next; | ||||
|     lfs2_block_t root[2]; | ||||
|     struct lfs2_mlist { | ||||
|         struct lfs2_mlist *next; | ||||
|         uint16_t id; | ||||
|         uint8_t type; | ||||
|         lfs_mdir_t m; | ||||
|         lfs2_mdir_t m; | ||||
|     } *mlist; | ||||
|     uint32_t seed; | ||||
| 
 | ||||
|     lfs_gstate_t gstate; | ||||
|     lfs_gstate_t gdisk; | ||||
|     lfs_gstate_t gdelta; | ||||
|     lfs2_gstate_t gstate; | ||||
|     lfs2_gstate_t gdisk; | ||||
|     lfs2_gstate_t gdelta; | ||||
| 
 | ||||
|     struct lfs_free { | ||||
|         lfs_block_t off; | ||||
|         lfs_block_t size; | ||||
|         lfs_block_t i; | ||||
|         lfs_block_t ack; | ||||
|     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 lfs_config *cfg; | ||||
|     lfs_size_t name_max; | ||||
|     lfs_size_t file_max; | ||||
|     lfs_size_t attr_max; | ||||
|     const struct lfs2_config *cfg; | ||||
|     lfs2_size_t name_max; | ||||
|     lfs2_size_t file_max; | ||||
|     lfs2_size_t attr_max; | ||||
| 
 | ||||
| #ifdef LFS_MIGRATE | ||||
|     struct lfs1 *lfs1; | ||||
| #ifdef LFS2_MIGRATE | ||||
|     struct lfs21 *lfs21; | ||||
| #endif | ||||
| } lfs_t; | ||||
| } lfs2_t; | ||||
| 
 | ||||
| 
 | ||||
| /// Filesystem functions ///
 | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // Format a block device with the littlefs
 | ||||
| //
 | ||||
| // Requires a littlefs object and config struct. This clobbers the littlefs
 | ||||
| @@ -429,85 +429,85 @@ typedef struct lfs { | ||||
| // 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); | ||||
| int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config); | ||||
| #endif | ||||
| 
 | ||||
| // 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
 | ||||
| // 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 lfs_mount(lfs_t *lfs, const struct lfs_config *config); | ||||
| 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 lfs_unmount(lfs_t *lfs); | ||||
| int lfs2_unmount(lfs2_t *lfs2); | ||||
| 
 | ||||
| /// General operations ///
 | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // 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); | ||||
| int lfs2_remove(lfs2_t *lfs2, const char *path); | ||||
| #endif | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // 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); | ||||
| int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath); | ||||
| #endif | ||||
| 
 | ||||
| // 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); | ||||
| 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 LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
 | ||||
| // to LFS2_ATTR_MAX bytes. When read, if the stored attribute is smaller than
 | ||||
| // the buffer, it will be padded with zeros. If the stored attribute is larger,
 | ||||
| // then it will be silently truncated. If no attribute is found, the error
 | ||||
| // LFS_ERR_NOATTR is returned and the buffer is filled with zeros.
 | ||||
| // LFS2_ERR_NOATTR is returned and the buffer is filled with zeros.
 | ||||
| //
 | ||||
| // Returns the size of the attribute, or a negative error code on failure.
 | ||||
| // 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); | ||||
| // or check for existence.
 | ||||
| lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, | ||||
|         uint8_t type, void *buffer, lfs2_size_t size); | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // 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
 | ||||
| // to LFS2_ATTR_MAX bytes. If an attribute is not found, it will be
 | ||||
| // implicitly created.
 | ||||
| //
 | ||||
| // 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); | ||||
| int lfs2_setattr(lfs2_t *lfs2, const char *path, | ||||
|         uint8_t type, const void *buffer, lfs2_size_t size); | ||||
| #endif | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // Removes a custom attribute
 | ||||
| //
 | ||||
| // If an attribute is not found, nothing happens.
 | ||||
| //
 | ||||
| // Returns a negative error code on failure.
 | ||||
| int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); | ||||
| int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type); | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| @@ -516,25 +516,25 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); | ||||
| // 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.
 | ||||
| // are values from the enum lfs2_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, | ||||
| 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 lfs_open_flags that are bitwise-ored together.
 | ||||
| // are values from the enum lfs2_open_flags that are bitwise-ored together.
 | ||||
| //
 | ||||
| // The config struct provides additional config options per file as described
 | ||||
| // 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, | ||||
| int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, | ||||
|         const char *path, int flags, | ||||
|         const struct lfs_file_config *config); | ||||
|         const struct lfs2_file_config *config); | ||||
| 
 | ||||
| // Close a file
 | ||||
| //
 | ||||
| @@ -542,92 +542,92 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
| // 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); | ||||
| 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 lfs_file_sync(lfs_t *lfs, lfs_file_t *file); | ||||
| int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file); | ||||
| 
 | ||||
| // Read data from file
 | ||||
| //
 | ||||
| // 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); | ||||
| lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, | ||||
|         void *buffer, lfs2_size_t size); | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // 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); | ||||
| lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, | ||||
|         const void *buffer, lfs2_size_t size); | ||||
| #endif | ||||
| 
 | ||||
| // Change the position of the file
 | ||||
| //
 | ||||
| // The change in position is determined by the offset and whence flag.
 | ||||
| // Returns the new position of the file, or a negative error code on failure.
 | ||||
| lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | ||||
|         lfs_soff_t off, int whence); | ||||
| lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, | ||||
|         lfs2_soff_t off, int whence); | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // 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); | ||||
| int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size); | ||||
| #endif | ||||
| 
 | ||||
| // Return the position of the file
 | ||||
| //
 | ||||
| // Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
 | ||||
| // Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_CUR)
 | ||||
| // Returns the position of the file, or a negative error code on failure.
 | ||||
| lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); | ||||
| lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file); | ||||
| 
 | ||||
| // Change the position of the file to the beginning of the file
 | ||||
| //
 | ||||
| // Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET)
 | ||||
| // Equivalent to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_SET)
 | ||||
| // Returns a negative error code on failure.
 | ||||
| int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); | ||||
| int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file); | ||||
| 
 | ||||
| // Return the size of the file
 | ||||
| //
 | ||||
| // Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
 | ||||
| // Similar to lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_END)
 | ||||
| // Returns the size of the file, or a negative error code on failure.
 | ||||
| lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); | ||||
| lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file); | ||||
| 
 | ||||
| 
 | ||||
| /// Directory operations ///
 | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifndef LFS2_READONLY | ||||
| // Create a directory
 | ||||
| //
 | ||||
| // Returns a negative error code on failure.
 | ||||
| int lfs_mkdir(lfs_t *lfs, const char *path); | ||||
| int lfs2_mkdir(lfs2_t *lfs2, const char *path); | ||||
| #endif | ||||
| 
 | ||||
| // 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); | ||||
| 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 lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); | ||||
| int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir); | ||||
| 
 | ||||
| // Read an entry in the directory
 | ||||
| //
 | ||||
| // Fills out the info structure, based on the specified file or directory.
 | ||||
| // Returns a positive value on success, 0 at the end of directory,
 | ||||
| // or a negative error code on failure.
 | ||||
| int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); | ||||
| int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info); | ||||
| 
 | ||||
| // Change the position of the directory
 | ||||
| //
 | ||||
| @@ -635,7 +635,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); | ||||
| // an absolute offset in the directory seek.
 | ||||
| //
 | ||||
| // Returns a negative error code on failure.
 | ||||
| int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); | ||||
| int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off); | ||||
| 
 | ||||
| // Return the position of the directory
 | ||||
| //
 | ||||
| @@ -643,12 +643,12 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); | ||||
| // sense, but does indicate the current position in the directory iteration.
 | ||||
| //
 | ||||
| // Returns the position of the directory, or a negative error code on failure.
 | ||||
| lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); | ||||
| lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir); | ||||
| 
 | ||||
| // Change the position of the directory to the beginning of the directory
 | ||||
| //
 | ||||
| // Returns a negative error code on failure.
 | ||||
| int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); | ||||
| int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir); | ||||
| 
 | ||||
| 
 | ||||
| /// Filesystem-level filesystem operations
 | ||||
| @@ -659,7 +659,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); | ||||
| // 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); | ||||
| lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2); | ||||
| 
 | ||||
| // Traverse through all blocks in use by the filesystem
 | ||||
| //
 | ||||
| @@ -668,13 +668,13 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); | ||||
| // 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); | ||||
| int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); | ||||
| 
 | ||||
| #ifndef LFS_READONLY | ||||
| #ifdef LFS_MIGRATE | ||||
| #ifndef LFS2_READONLY | ||||
| #ifdef LFS2_MIGRATE | ||||
| // Attempts to migrate a previous version of littlefs
 | ||||
| //
 | ||||
| // Behaves similarly to the lfs_format function. Attempts to mount
 | ||||
| // Behaves similarly to the lfs2_format function. Attempts to mount
 | ||||
| // the previous version of littlefs and update the filesystem so it can be
 | ||||
| // mounted with the current version of littlefs.
 | ||||
| //
 | ||||
| @@ -683,7 +683,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | ||||
| // be zeroed for defaults and backwards compatibility.
 | ||||
| //
 | ||||
| // Returns a negative error code on failure.
 | ||||
| int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); | ||||
| int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg); | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| @@ -1,17 +1,17 @@ | ||||
| /*
 | ||||
|  * lfs util functions | ||||
|  * lfs2 util functions | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "lfs_util.h" | ||||
| #include "lfs2_util.h" | ||||
| 
 | ||||
| // Only compile if user does not provide custom config
 | ||||
| #ifndef LFS_CONFIG | ||||
| #ifndef LFS2_CONFIG | ||||
| 
 | ||||
| 
 | ||||
| // Software CRC implementation with small lookup table
 | ||||
| uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { | ||||
| uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { | ||||
|     static const uint32_t rtable[16] = { | ||||
|         0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, | ||||
|         0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, | ||||
| @@ -1,22 +1,22 @@ | ||||
| /*
 | ||||
|  * lfs utility functions | ||||
|  * lfs2 utility functions | ||||
|  * | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_UTIL_H | ||||
| #define LFS_UTIL_H | ||||
| #ifndef LFS2_UTIL_H | ||||
| #define LFS2_UTIL_H | ||||
| 
 | ||||
| // Users can override lfs_util.h with their own configuration by defining
 | ||||
| // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
 | ||||
| // 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).
 | ||||
| //
 | ||||
| // 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
 | ||||
| // 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
 | ||||
| // and modifying as needed.
 | ||||
| #ifdef LFS_CONFIG | ||||
| #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) | ||||
| #define LFS_STRINGIZE2(x) #x | ||||
| #include LFS_STRINGIZE(LFS_CONFIG) | ||||
| #ifdef LFS2_CONFIG | ||||
| #define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x) | ||||
| #define LFS2_STRINGIZE2(x) #x | ||||
| #include LFS2_STRINGIZE(LFS2_CONFIG) | ||||
| #else | ||||
| 
 | ||||
| // System includes
 | ||||
| @@ -25,16 +25,16 @@ | ||||
| #include <string.h> | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| #ifndef LFS_NO_MALLOC | ||||
| #ifndef LFS2_NO_MALLOC | ||||
| #include <stdlib.h> | ||||
| #endif | ||||
| #ifndef LFS_NO_ASSERT | ||||
| #ifndef LFS2_NO_ASSERT | ||||
| #include <assert.h> | ||||
| #endif | ||||
| #if !defined(LFS_NO_DEBUG) || \ | ||||
|         !defined(LFS_NO_WARN) || \ | ||||
|         !defined(LFS_NO_ERROR) || \ | ||||
|         defined(LFS_YES_TRACE) | ||||
| #if !defined(LFS2_NO_DEBUG) || \ | ||||
|         !defined(LFS2_NO_WARN) || \ | ||||
|         !defined(LFS2_NO_ERROR) || \ | ||||
|         defined(LFS2_YES_TRACE) | ||||
| #include <stdio.h> | ||||
| #endif | ||||
| 
 | ||||
| @@ -49,81 +49,81 @@ extern "C" | ||||
| // code footprint
 | ||||
| 
 | ||||
| // Logging functions
 | ||||
| #ifndef LFS_TRACE | ||||
| #ifdef LFS_YES_TRACE | ||||
| #define LFS_TRACE_(fmt, ...) \ | ||||
| #ifndef LFS2_TRACE | ||||
| #ifdef LFS2_YES_TRACE | ||||
| #define LFS2_TRACE_(fmt, ...) \ | ||||
|     printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") | ||||
| #define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "") | ||||
| #else | ||||
| #define LFS_TRACE(...) | ||||
| #define LFS2_TRACE(...) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef LFS_DEBUG | ||||
| #ifndef LFS_NO_DEBUG | ||||
| #define LFS_DEBUG_(fmt, ...) \ | ||||
| #ifndef LFS2_DEBUG | ||||
| #ifndef LFS2_NO_DEBUG | ||||
| #define LFS2_DEBUG_(fmt, ...) \ | ||||
|     printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") | ||||
| #define LFS2_DEBUG(...) LFS2_DEBUG_(__VA_ARGS__, "") | ||||
| #else | ||||
| #define LFS_DEBUG(...) | ||||
| #define LFS2_DEBUG(...) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef LFS_WARN | ||||
| #ifndef LFS_NO_WARN | ||||
| #define LFS_WARN_(fmt, ...) \ | ||||
| #ifndef LFS2_WARN | ||||
| #ifndef LFS2_NO_WARN | ||||
| #define LFS2_WARN_(fmt, ...) \ | ||||
|     printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") | ||||
| #define LFS2_WARN(...) LFS2_WARN_(__VA_ARGS__, "") | ||||
| #else | ||||
| #define LFS_WARN(...) | ||||
| #define LFS2_WARN(...) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef LFS_ERROR | ||||
| #ifndef LFS_NO_ERROR | ||||
| #define LFS_ERROR_(fmt, ...) \ | ||||
| #ifndef LFS2_ERROR | ||||
| #ifndef LFS2_NO_ERROR | ||||
| #define LFS2_ERROR_(fmt, ...) \ | ||||
|     printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) | ||||
| #define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") | ||||
| #define LFS2_ERROR(...) LFS2_ERROR_(__VA_ARGS__, "") | ||||
| #else | ||||
| #define LFS_ERROR(...) | ||||
| #define LFS2_ERROR(...) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| // Runtime assertions
 | ||||
| #ifndef LFS_ASSERT | ||||
| #ifndef LFS_NO_ASSERT | ||||
| #define LFS_ASSERT(test) assert(test) | ||||
| #ifndef LFS2_ASSERT | ||||
| #ifndef LFS2_NO_ASSERT | ||||
| #define LFS2_ASSERT(test) assert(test) | ||||
| #else | ||||
| #define LFS_ASSERT(test) | ||||
| #define LFS2_ASSERT(test) | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // Builtin functions, these may be replaced by more efficient
 | ||||
| // toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
 | ||||
| // toolchain-specific implementations. LFS2_NO_INTRINSICS falls back to a more
 | ||||
| // expensive basic C implementation for debugging purposes
 | ||||
| 
 | ||||
| // Min/max functions for unsigned 32-bit numbers
 | ||||
| static inline uint32_t lfs_max(uint32_t a, uint32_t b) { | ||||
| static inline uint32_t lfs2_max(uint32_t a, uint32_t b) { | ||||
|     return (a > b) ? a : b; | ||||
| } | ||||
| 
 | ||||
| static inline uint32_t lfs_min(uint32_t a, uint32_t b) { | ||||
| static inline uint32_t lfs2_min(uint32_t a, uint32_t b) { | ||||
|     return (a < b) ? a : b; | ||||
| } | ||||
| 
 | ||||
| // Align to nearest multiple of a size
 | ||||
| static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { | ||||
| static inline uint32_t lfs2_aligndown(uint32_t a, uint32_t alignment) { | ||||
|     return a - (a % alignment); | ||||
| } | ||||
| 
 | ||||
| static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { | ||||
|     return lfs_aligndown(a + alignment-1, alignment); | ||||
| static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) { | ||||
|     return lfs2_aligndown(a + alignment-1, alignment); | ||||
| } | ||||
| 
 | ||||
| // Find the smallest power of 2 greater than or equal to a
 | ||||
| static inline uint32_t lfs_npw2(uint32_t a) { | ||||
| #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) | ||||
| static inline uint32_t lfs2_npw2(uint32_t a) { | ||||
| #if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) | ||||
|     return 32 - __builtin_clz(a-1); | ||||
| #else | ||||
|     uint32_t r = 0; | ||||
| @@ -138,18 +138,18 @@ static inline uint32_t lfs_npw2(uint32_t a) { | ||||
| } | ||||
| 
 | ||||
| // Count the number of trailing binary zeros in a
 | ||||
| // lfs_ctz(0) may be undefined
 | ||||
| static inline uint32_t lfs_ctz(uint32_t a) { | ||||
| #if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) | ||||
| // lfs2_ctz(0) may be undefined
 | ||||
| static inline uint32_t lfs2_ctz(uint32_t a) { | ||||
| #if !defined(LFS2_NO_INTRINSICS) && defined(__GNUC__) | ||||
|     return __builtin_ctz(a); | ||||
| #else | ||||
|     return lfs_npw2((a & -a) + 1) - 1; | ||||
|     return lfs2_npw2((a & -a) + 1) - 1; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| // Count the number of binary ones in a
 | ||||
| static inline uint32_t lfs_popc(uint32_t a) { | ||||
| #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) | ||||
| static inline uint32_t lfs2_popc(uint32_t a) { | ||||
| #if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) | ||||
|     return __builtin_popcount(a); | ||||
| #else | ||||
|     a = a - ((a >> 1) & 0x55555555); | ||||
| @@ -160,18 +160,18 @@ static inline uint32_t lfs_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 lfs_scmp(uint32_t a, uint32_t b) { | ||||
| static inline int lfs2_scmp(uint32_t a, uint32_t b) { | ||||
|     return (int)(unsigned)(a - b); | ||||
| } | ||||
| 
 | ||||
| // Convert between 32-bit little-endian and native order
 | ||||
| static inline uint32_t lfs_fromle32(uint32_t a) { | ||||
| #if !defined(LFS_NO_INTRINSICS) && ( \ | ||||
| static inline uint32_t lfs2_fromle32(uint32_t a) { | ||||
| #if !defined(LFS2_NO_INTRINSICS) && ( \ | ||||
|     (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) | ||||
|     return a; | ||||
| #elif !defined(LFS_NO_INTRINSICS) && ( \ | ||||
| #elif !defined(LFS2_NO_INTRINSICS) && ( \ | ||||
|     (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) | ||||
| @@ -184,18 +184,18 @@ static inline uint32_t lfs_fromle32(uint32_t a) { | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static inline uint32_t lfs_tole32(uint32_t a) { | ||||
|     return lfs_fromle32(a); | ||||
| static inline uint32_t lfs2_tole32(uint32_t a) { | ||||
|     return lfs2_fromle32(a); | ||||
| } | ||||
| 
 | ||||
| // Convert between 32-bit big-endian and native order
 | ||||
| static inline uint32_t lfs_frombe32(uint32_t a) { | ||||
| #if !defined(LFS_NO_INTRINSICS) && ( \ | ||||
| static inline uint32_t lfs2_frombe32(uint32_t a) { | ||||
| #if !defined(LFS2_NO_INTRINSICS) && ( \ | ||||
|     (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) | ||||
|     return __builtin_bswap32(a); | ||||
| #elif !defined(LFS_NO_INTRINSICS) && ( \ | ||||
| #elif !defined(LFS2_NO_INTRINSICS) && ( \ | ||||
|     (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \ | ||||
|     (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) | ||||
| @@ -208,17 +208,17 @@ static inline uint32_t lfs_frombe32(uint32_t a) { | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static inline uint32_t lfs_tobe32(uint32_t a) { | ||||
|     return lfs_frombe32(a); | ||||
| static inline uint32_t lfs2_tobe32(uint32_t a) { | ||||
|     return lfs2_frombe32(a); | ||||
| } | ||||
| 
 | ||||
| // Calculate CRC-32 with polynomial = 0x04c11db7
 | ||||
| uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); | ||||
| uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size); | ||||
| 
 | ||||
| // Allocate memory, only used if buffers are not provided to littlefs
 | ||||
| // Note, memory must be 64-bit aligned
 | ||||
| static inline void *lfs_malloc(size_t size) { | ||||
| #ifndef LFS_NO_MALLOC | ||||
| static inline void *lfs2_malloc(size_t size) { | ||||
| #ifndef LFS2_NO_MALLOC | ||||
|     return malloc(size); | ||||
| #else | ||||
|     (void)size; | ||||
| @@ -227,8 +227,8 @@ static inline void *lfs_malloc(size_t size) { | ||||
| } | ||||
| 
 | ||||
| // Deallocate memory, only used if buffers are not provided to littlefs
 | ||||
| static inline void lfs_free(void *p) { | ||||
| #ifndef LFS_NO_MALLOC | ||||
| static inline void lfs2_free(void *p) { | ||||
| #ifndef LFS2_NO_MALLOC | ||||
|     free(p); | ||||
| #else | ||||
|     (void)p; | ||||
| @@ -3,8 +3,8 @@ | ||||
| import re | ||||
| import sys | ||||
|  | ||||
| PATTERN = ['LFS_ASSERT', 'assert'] | ||||
| PREFIX = 'LFS' | ||||
| PATTERN = ['LFS2_ASSERT', 'assert'] | ||||
| PREFIX = 'LFS2' | ||||
| MAXWIDTH = 16 | ||||
|  | ||||
| ASSERT = "__{PREFIX}_ASSERT_{TYPE}_{COMP}" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| # conflict at compile time. | ||||
| # | ||||
| # example: | ||||
| # $ ./scripts/prefix.py lfs2 | ||||
| # $ ./scripts/prefix.py lfs22 | ||||
|  | ||||
| import os | ||||
| import os.path | ||||
| @@ -16,7 +16,7 @@ import tempfile | ||||
| import shutil | ||||
| import subprocess | ||||
|  | ||||
| DEFAULT_PREFIX = "lfs" | ||||
| DEFAULT_PREFIX = "lfs2" | ||||
|  | ||||
| def subn(from_prefix, to_prefix, name): | ||||
|     name, count1 = re.subn('\\b'+from_prefix, to_prefix, name) | ||||
|   | ||||
| @@ -67,63 +67,63 @@ endif | ||||
| """ | ||||
| GLOBALS = """ | ||||
| //////////////// AUTOGENERATED TEST //////////////// | ||||
| #include "lfs.h" | ||||
| #include "bd/lfs_testbd.h" | ||||
| #include "lfs2.h" | ||||
| #include "bd/lfs2_testbd.h" | ||||
| #include <stdio.h> | ||||
| extern const char *lfs_testbd_path; | ||||
| extern uint32_t lfs_testbd_cycles; | ||||
| extern const char *lfs2_testbd_path; | ||||
| extern uint32_t lfs2_testbd_cycles; | ||||
| """ | ||||
| DEFINES = { | ||||
|     'LFS_READ_SIZE': 16, | ||||
|     'LFS_PROG_SIZE': 'LFS_READ_SIZE', | ||||
|     'LFS_BLOCK_SIZE': 512, | ||||
|     'LFS_BLOCK_COUNT': 1024, | ||||
|     'LFS_BLOCK_CYCLES': -1, | ||||
|     'LFS_CACHE_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)', | ||||
|     'LFS_LOOKAHEAD_SIZE': 16, | ||||
|     'LFS_ERASE_VALUE': 0xff, | ||||
|     'LFS_ERASE_CYCLES': 0, | ||||
|     'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_READ_SIZE': 16, | ||||
|     'LFS2_PROG_SIZE': 'LFS2_READ_SIZE', | ||||
|     'LFS2_BLOCK_SIZE': 512, | ||||
|     'LFS2_BLOCK_COUNT': 1024, | ||||
|     'LFS2_BLOCK_CYCLES': -1, | ||||
|     'LFS2_CACHE_SIZE': '(64 % LFS2_PROG_SIZE == 0 ? 64 : LFS2_PROG_SIZE)', | ||||
|     'LFS2_LOOKAHEAD_SIZE': 16, | ||||
|     'LFS2_ERASE_VALUE': 0xff, | ||||
|     'LFS2_ERASE_CYCLES': 0, | ||||
|     'LFS2_BADBLOCK_BEHAVIOR': 'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
| } | ||||
| PROLOGUE = """ | ||||
|     // prologue | ||||
|     __attribute__((unused)) lfs_t lfs; | ||||
|     __attribute__((unused)) lfs_testbd_t bd; | ||||
|     __attribute__((unused)) lfs_file_t file; | ||||
|     __attribute__((unused)) lfs_dir_t dir; | ||||
|     __attribute__((unused)) struct lfs_info info; | ||||
|     __attribute__((unused)) lfs2_t lfs2; | ||||
|     __attribute__((unused)) lfs2_testbd_t bd; | ||||
|     __attribute__((unused)) lfs2_file_t file; | ||||
|     __attribute__((unused)) lfs2_dir_t dir; | ||||
|     __attribute__((unused)) struct lfs2_info info; | ||||
|     __attribute__((unused)) char path[1024]; | ||||
|     __attribute__((unused)) uint8_t buffer[1024]; | ||||
|     __attribute__((unused)) lfs_size_t size; | ||||
|     __attribute__((unused)) lfs2_size_t size; | ||||
|     __attribute__((unused)) int err; | ||||
|      | ||||
|     __attribute__((unused)) const struct lfs_config cfg = { | ||||
|     __attribute__((unused)) const struct lfs2_config cfg = { | ||||
|         .context        = &bd, | ||||
|         .read           = lfs_testbd_read, | ||||
|         .prog           = lfs_testbd_prog, | ||||
|         .erase          = lfs_testbd_erase, | ||||
|         .sync           = lfs_testbd_sync, | ||||
|         .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_size = LFS_LOOKAHEAD_SIZE, | ||||
|         .read           = lfs2_testbd_read, | ||||
|         .prog           = lfs2_testbd_prog, | ||||
|         .erase          = lfs2_testbd_erase, | ||||
|         .sync           = lfs2_testbd_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, | ||||
|     }; | ||||
|  | ||||
|     __attribute__((unused)) const struct lfs_testbd_config bdcfg = { | ||||
|         .erase_value        = LFS_ERASE_VALUE, | ||||
|         .erase_cycles       = LFS_ERASE_CYCLES, | ||||
|         .badblock_behavior  = LFS_BADBLOCK_BEHAVIOR, | ||||
|         .power_cycles       = lfs_testbd_cycles, | ||||
|     __attribute__((unused)) const struct lfs2_testbd_config bdcfg = { | ||||
|         .erase_value        = LFS2_ERASE_VALUE, | ||||
|         .erase_cycles       = LFS2_ERASE_CYCLES, | ||||
|         .badblock_behavior  = LFS2_BADBLOCK_BEHAVIOR, | ||||
|         .power_cycles       = lfs2_testbd_cycles, | ||||
|     }; | ||||
|  | ||||
|     lfs_testbd_createcfg(&cfg, lfs_testbd_path, &bdcfg) => 0; | ||||
|     lfs2_testbd_createcfg(&cfg, lfs2_testbd_path, &bdcfg) => 0; | ||||
| """ | ||||
| EPILOGUE = """ | ||||
|     // epilogue | ||||
|     lfs_testbd_destroy(&cfg) => 0; | ||||
|     lfs2_testbd_destroy(&cfg) => 0; | ||||
| """ | ||||
| PASS = '\033[32m✓\033[0m' | ||||
| FAIL = '\033[31m✗\033[0m' | ||||
| @@ -335,7 +335,7 @@ class ValgrindTestCase(TestCase): | ||||
|  | ||||
|     def test(self, exec=[], **args): | ||||
|         verbose = args.get('verbose') | ||||
|         uninit = (self.defines.get('LFS_ERASE_VALUE', None) == -1) | ||||
|         uninit = (self.defines.get('LFS2_ERASE_VALUE', None) == -1) | ||||
|         exec = [ | ||||
|             'valgrind', | ||||
|             '--leak-check=full', | ||||
| @@ -529,13 +529,13 @@ class TestSuite: | ||||
|             case.build(tfs[case.in_], **args) | ||||
|  | ||||
|         tf.write('\n') | ||||
|         tf.write('const char *lfs_testbd_path;\n') | ||||
|         tf.write('uint32_t lfs_testbd_cycles;\n') | ||||
|         tf.write('const char *lfs2_testbd_path;\n') | ||||
|         tf.write('uint32_t lfs2_testbd_cycles;\n') | ||||
|         tf.write('int main(int argc, char **argv) {\n') | ||||
|         tf.write(4*' '+'int case_         = (argc > 1) ? atoi(argv[1]) : 0;\n') | ||||
|         tf.write(4*' '+'int perm          = (argc > 2) ? atoi(argv[2]) : 0;\n') | ||||
|         tf.write(4*' '+'lfs_testbd_path   = (argc > 3) ? argv[3] : NULL;\n') | ||||
|         tf.write(4*' '+'lfs_testbd_cycles = (argc > 4) ? atoi(argv[4]) : 0;\n') | ||||
|         tf.write(4*' '+'lfs2_testbd_path   = (argc > 3) ? argv[3] : NULL;\n') | ||||
|         tf.write(4*' '+'lfs2_testbd_cycles = (argc > 4) ? atoi(argv[4]) : 0;\n') | ||||
|         for perm in self.perms: | ||||
|             # test declaration | ||||
|             tf.write(4*' '+'extern void test_case%d(%s);\n' % ( | ||||
| @@ -565,7 +565,7 @@ class TestSuite: | ||||
|                     path=self.path)) | ||||
|                 mk.write('\n') | ||||
|  | ||||
|             # add truely global defines globally | ||||
|             # add truly global defines globally | ||||
|             for k, v in sorted(self.defines.items()): | ||||
|                 mk.write('%s.test: override CFLAGS += -D%s=%r\n' | ||||
|                     % (self.path, k, v)) | ||||
| @@ -656,7 +656,7 @@ def main(**args): | ||||
|         for path in glob.glob(testpath): | ||||
|             suites.append(TestSuite(path, classes, defines, filter, **args)) | ||||
|  | ||||
|     # sort for reproducability | ||||
|     # sort for reproducibility | ||||
|     suites = sorted(suites) | ||||
|  | ||||
|     # generate permutations | ||||
|   | ||||
| @@ -1,409 +1,409 @@ | ||||
| # allocator tests | ||||
| # note for these to work there are a number constraints on the device geometry | ||||
| if = 'LFS_BLOCK_CYCLES == -1' | ||||
| if = 'LFS2_BLOCK_CYCLES == -1' | ||||
|  | ||||
| [[case]] # parallel allocation test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
|     lfs_file_t files[FILES]; | ||||
|     lfs2_file_t files[FILES]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "breakfast") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs_file_open(&lfs, &files[n], path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|         lfs2_file_open(&lfs2, &files[n], path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     } | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         size = strlen(names[n]); | ||||
|         for (lfs_size_t i = 0; i < SIZE; i += size) { | ||||
|             lfs_file_write(&lfs, &files[n], names[n], size) => size; | ||||
|         for (lfs2_size_t i = 0; i < SIZE; i += size) { | ||||
|             lfs2_file_write(&lfs2, &files[n], names[n], size) => size; | ||||
|         } | ||||
|     } | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         lfs_file_close(&lfs, &files[n]) => 0; | ||||
|         lfs2_file_close(&lfs2, &files[n]) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         size = strlen(names[n]); | ||||
|         for (lfs_size_t i = 0; i < SIZE; i += size) { | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         for (lfs2_size_t i = 0; i < SIZE; i += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, names[n], size) == 0); | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # serial allocation test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "breakfast") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs_file_open(&lfs, &file, path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|         size = strlen(names[n]); | ||||
|         memcpy(buffer, names[n], size); | ||||
|         for (int i = 0; i < SIZE; i += size) { | ||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         size = strlen(names[n]); | ||||
|         for (int i = 0; i < SIZE; i += size) { | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, names[n], size) == 0); | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # parallel allocation reuse test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| define.CYCLES = [1, 10] | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
|     lfs_file_t files[FILES]; | ||||
|     lfs2_file_t files[FILES]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (int c = 0; c < CYCLES; c++) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs_mkdir(&lfs, "breakfast") => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs_file_open(&lfs, &files[n], path, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|             lfs2_file_open(&lfs2, &files[n], path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|         } | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             size = strlen(names[n]); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs_file_write(&lfs, &files[n], names[n], size) => size; | ||||
|                 lfs2_file_write(&lfs2, &files[n], names[n], size) => size; | ||||
|             } | ||||
|         } | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             lfs_file_close(&lfs, &files[n]) => 0; | ||||
|             lfs2_file_close(&lfs2, &files[n]) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             size = strlen(names[n]); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|                 lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|                 assert(memcmp(buffer, names[n], size) == 0); | ||||
|             } | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs_remove(&lfs, path) => 0; | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|         lfs_remove(&lfs, "breakfast") => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_remove(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
|  | ||||
| [[case]] # serial allocation reuse test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| define.CYCLES = [1, 10] | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (int c = 0; c < CYCLES; c++) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs_mkdir(&lfs, "breakfast") => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             lfs_mount(&lfs, &cfg) => 0; | ||||
|             lfs2_mount(&lfs2, &cfg) => 0; | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs_file_open(&lfs, &file, path, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|             size = strlen(names[n]); | ||||
|             memcpy(buffer, names[n], size); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|                 lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|             } | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs_unmount(&lfs) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|             lfs2_unmount(&lfs2) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             size = strlen(names[n]); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|                 lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|                 assert(memcmp(buffer, names[n], size) == 0); | ||||
|             } | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs_remove(&lfs, path) => 0; | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|         lfs_remove(&lfs, "breakfast") => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_remove(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
|  | ||||
| [[case]] # exhaustion test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     size = strlen("exhaustion"); | ||||
|     memcpy(buffer, "exhaustion", size); | ||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     lfs_ssize_t res; | ||||
|     lfs2_ssize_t res; | ||||
|     while (true) { | ||||
|         res = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         if (res < 0) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         res => size; | ||||
|     } | ||||
|     res => LFS_ERR_NOSPC; | ||||
|     res => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_RDONLY); | ||||
|     size = strlen("exhaustion"); | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "exhaustion", size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # exhaustion wraparound test | ||||
| define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)' | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-4)) / 3)' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     size = strlen("buffering"); | ||||
|     memcpy(buffer, "buffering", size); | ||||
|     for (int i = 0; i < SIZE; i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_remove(&lfs, "padding") => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, "padding") => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     size = strlen("exhaustion"); | ||||
|     memcpy(buffer, "exhaustion", size); | ||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     lfs_ssize_t res; | ||||
|     lfs2_ssize_t res; | ||||
|     while (true) { | ||||
|         res = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         if (res < 0) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         res => size; | ||||
|     } | ||||
|     res => LFS_ERR_NOSPC; | ||||
|     res => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_RDONLY); | ||||
|     size = strlen("exhaustion"); | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "exhaustion", size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_remove(&lfs, "exhaustion") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # dir exhaustion test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // find out max file size | ||||
|     lfs_mkdir(&lfs, "exhaustiondir") => 0; | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir") => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     int count = 0; | ||||
|     while (true) { | ||||
|         err = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         err = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         if (err < 0) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         count += 1; | ||||
|     } | ||||
|     err => LFS_ERR_NOSPC; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     err => LFS2_ERR_NOSPC; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_remove(&lfs, "exhaustion") => 0; | ||||
|     lfs_remove(&lfs, "exhaustiondir") => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustiondir") => 0; | ||||
|  | ||||
|     // see if dir fits with max file size | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "exhaustiondir") => 0; | ||||
|     lfs_remove(&lfs, "exhaustiondir") => 0; | ||||
|     lfs_remove(&lfs, "exhaustion") => 0; | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir") => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustiondir") => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|  | ||||
|     // see if dir fits with > max file size | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     for (int i = 0; i < count+1; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir") => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     lfs_remove(&lfs, "exhaustion") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # what if we have a bad block during an allocation scan? | ||||
| in = "lfs.c" | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' | ||||
| in = "lfs2.c" | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = 'LFS2_TESTBD_BADBLOCK_READERROR' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     // first fill to exhaustion to find available space | ||||
|     lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "waka"); | ||||
|     size = strlen("waka"); | ||||
|     lfs_size_t filesize = 0; | ||||
|     lfs2_size_t filesize = 0; | ||||
|     while (true) { | ||||
|         lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); | ||||
|         if (res == LFS_ERR_NOSPC) { | ||||
|         lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_NOSPC); | ||||
|         if (res == LFS2_ERR_NOSPC) { | ||||
|             break; | ||||
|         } | ||||
|         filesize += size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // now fill all but a couple of blocks of the filesystem with data | ||||
|     filesize -= 3*LFS_BLOCK_SIZE; | ||||
|     lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     filesize -= 3*LFS2_BLOCK_SIZE; | ||||
|     lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "waka"); | ||||
|     size = strlen("waka"); | ||||
|     for (lfs_size_t i = 0; i < filesize/size; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_size_t i = 0; i < filesize/size; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // also save head of file so we can error during lookahead scan | ||||
|     lfs_block_t fileblock = file.ctz.head; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_block_t fileblock = file.ctz.head; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // remount to force an alloc scan | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // but mark the head of our file as a "bad block", this is force our | ||||
|     // scan to bail early | ||||
|     lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; | ||||
|     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "ghost", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "chomp"); | ||||
|     size = strlen("chomp"); | ||||
|     while (true) { | ||||
|         lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT); | ||||
|         if (res == LFS_ERR_CORRUPT) { | ||||
|         lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_CORRUPT); | ||||
|         if (res == LFS2_ERR_CORRUPT) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // now reverse the "bad block" and try to write the file again until we | ||||
|     // run out of space | ||||
|     lfs_testbd_setwear(&cfg, fileblock, 0) => 0; | ||||
|     lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_testbd_setwear(&cfg, fileblock, 0) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "ghost", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "chomp"); | ||||
|     size = strlen("chomp"); | ||||
|     while (true) { | ||||
|         lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); | ||||
|         if (res == LFS_ERR_NOSPC) { | ||||
|         lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_NOSPC); | ||||
|         if (res == LFS2_ERR_NOSPC) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // check that the disk isn't hurt | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_RDONLY) => 0; | ||||
|     strcpy((char*)buffer, "waka"); | ||||
|     size = strlen("waka"); | ||||
|     for (lfs_size_t i = 0; i < filesize/size; i++) { | ||||
|     for (lfs2_size_t i = 0; i < filesize/size; i++) { | ||||
|         uint8_t rbuffer[4]; | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
|  | ||||
| @@ -412,242 +412,242 @@ code = ''' | ||||
| # should be removed and replaced with generalized tests. | ||||
|  | ||||
| [[case]] # chained dir exhaustion test | ||||
| define.LFS_BLOCK_SIZE = 512 | ||||
| define.LFS_BLOCK_COUNT = 1024 | ||||
| if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // find out max file size | ||||
|     lfs_mkdir(&lfs, "exhaustiondir") => 0; | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir") => 0; | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); | ||||
|         lfs_mkdir(&lfs, path) => 0; | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     int count = 0; | ||||
|     while (true) { | ||||
|         err = lfs_file_write(&lfs, &file, buffer, size); | ||||
|         err = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         if (err < 0) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         count += 1; | ||||
|     } | ||||
|     err => LFS_ERR_NOSPC; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     err => LFS2_ERR_NOSPC; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_remove(&lfs, "exhaustion") => 0; | ||||
|     lfs_remove(&lfs, "exhaustiondir") => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustiondir") => 0; | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); | ||||
|         lfs_remove(&lfs, path) => 0; | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     // see that chained dir fails | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     for (int i = 0; i < count+1; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); | ||||
|         lfs_mkdir(&lfs, path) => 0; | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir") => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     // shorten file to try a second chained dir | ||||
|     while (true) { | ||||
|         err = lfs_mkdir(&lfs, "exhaustiondir"); | ||||
|         if (err != LFS_ERR_NOSPC) { | ||||
|         err = lfs2_mkdir(&lfs2, "exhaustiondir"); | ||||
|         if (err != LFS2_ERR_NOSPC) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         lfs_ssize_t filesize = lfs_file_size(&lfs, &file); | ||||
|         lfs2_ssize_t filesize = lfs2_file_size(&lfs2, &file); | ||||
|         filesize > 0 => true; | ||||
|  | ||||
|         lfs_file_truncate(&lfs, &file, filesize - size) => 0; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|         lfs2_file_truncate(&lfs2, &file, filesize - size) => 0; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     } | ||||
|     err => 0; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir2") => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # split dir test | ||||
| define.LFS_BLOCK_SIZE = 512 | ||||
| define.LFS_BLOCK_COUNT = 1024 | ||||
| if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // create one block hole for half a directory | ||||
|     lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { | ||||
|     lfs2_file_open(&lfs2, &file, "bump", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     for (lfs2_size_t i = 0; i < cfg.block_size; i += 2) { | ||||
|         memcpy(&buffer[i], "hi", 2); | ||||
|     } | ||||
|     lfs_file_write(&lfs, &file, buffer, cfg.block_size) => cfg.block_size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, cfg.block_size) => cfg.block_size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < (cfg.block_count-4)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // remount to force reset of lookahead | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // open hole | ||||
|     lfs_remove(&lfs, "bump") => 0; | ||||
|     lfs2_remove(&lfs2, "bump") => 0; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "splitdir") => 0; | ||||
|     lfs_file_open(&lfs, &file, "splitdir/bump", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { | ||||
|     lfs2_mkdir(&lfs2, "splitdir") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "splitdir/bump", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     for (lfs2_size_t i = 0; i < cfg.block_size; i += 2) { | ||||
|         memcpy(&buffer[i], "hi", 2); | ||||
|     } | ||||
|     lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, 2*cfg.block_size) => LFS2_ERR_NOSPC; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # outdated lookahead test | ||||
| define.LFS_BLOCK_SIZE = 512 | ||||
| define.LFS_BLOCK_COUNT = 1024 | ||||
| if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // fill completely with two files | ||||
|     lfs_file_open(&lfs, &file, "exhaustion1", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion1", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "exhaustion2", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion2", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // remount to force reset of lookahead | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // rewrite one file | ||||
|     lfs_file_open(&lfs, &file, "exhaustion1", | ||||
|             LFS_O_WRONLY | LFS_O_TRUNC) => 0; | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion1", | ||||
|             LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // rewrite second file, this requires lookahead does not | ||||
|     // use old population | ||||
|     lfs_file_open(&lfs, &file, "exhaustion2", | ||||
|             LFS_O_WRONLY | LFS_O_TRUNC) => 0; | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion2", | ||||
|             LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # outdated lookahead and split dir test | ||||
| define.LFS_BLOCK_SIZE = 512 | ||||
| define.LFS_BLOCK_COUNT = 1024 | ||||
| if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // fill completely with two files | ||||
|     lfs_file_open(&lfs, &file, "exhaustion1", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion1", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "exhaustion2", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion2", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // remount to force reset of lookahead | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // rewrite one file with a hole of one block | ||||
|     lfs_file_open(&lfs, &file, "exhaustion1", | ||||
|             LFS_O_WRONLY | LFS_O_TRUNC) => 0; | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion1", | ||||
|             LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs_size_t i = 0; | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); | ||||
|             i += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // try to allocate a directory, should fail! | ||||
|     lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; | ||||
|     lfs2_mkdir(&lfs2, "split") => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     // file should not fail | ||||
|     lfs_file_open(&lfs, &file, "notasplit", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "notasplit", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -1,304 +1,304 @@ | ||||
| [[case]] # set/get attribute | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "hello") => 0; | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     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; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|  | ||||
|     lfs_removeattr(&lfs, "hello", 'B') => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => LFS_ERR_NOATTR; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|  | ||||
|     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; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 3; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 9; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     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_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     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; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # set/get root attribute | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "hello") => 0; | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     lfs_setattr(&lfs, "/", 'A', "aaaa",   4) => 0; | ||||
|     lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; | ||||
|     lfs_setattr(&lfs, "/", 'C', "ccccc",  5) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'B', "", 0) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|  | ||||
|     lfs_removeattr(&lfs, "/", 'B') => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => LFS_ERR_NOATTR; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 3; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     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; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||
|     lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 9; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     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_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  9) => 9; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; | ||||
|     lfs2_getattr(&lfs2, "/", 'A', buffer,    4) => 4; | ||||
|     lfs2_getattr(&lfs2, "/", 'B', buffer+4,  9) => 9; | ||||
|     lfs2_getattr(&lfs2, "/", 'C', buffer+13, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # set/get file attribute | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "hello") => 0; | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     struct lfs_attr attrs1[] = { | ||||
|     struct lfs2_attr attrs1[] = { | ||||
|         {'A', buffer,    4}, | ||||
|         {'B', buffer+4,  6}, | ||||
|         {'C', buffer+10, 5}, | ||||
|     }; | ||||
|     struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; | ||||
|     struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; | ||||
|  | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer,    "aaaa",   4); | ||||
|     memcpy(buffer+4,  "bbbbbb", 6); | ||||
|     memcpy(buffer+10, "ccccc",  5); | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     attrs1[1].size = 0; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 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; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer+4,  "dddddd", 6); | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     attrs1[1].size = 3; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer+4,  "eee", 3); | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|  | ||||
|     attrs1[0].size = LFS_ATTR_MAX+1; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) | ||||
|         => LFS_ERR_NOSPC; | ||||
|     attrs1[0].size = LFS2_ATTR_MAX+1; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) | ||||
|         => LFS2_ERR_NOSPC; | ||||
|  | ||||
|     struct lfs_attr attrs2[] = { | ||||
|     struct lfs2_attr attrs2[] = { | ||||
|         {'A', buffer,    4}, | ||||
|         {'B', buffer+4,  9}, | ||||
|         {'C', buffer+13, 5}, | ||||
|     }; | ||||
|     struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; | ||||
|     struct lfs2_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDWR, &cfg2) => 0; | ||||
|     memcpy(buffer+4,  "fffffffff", 9); | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     attrs1[0].size = 4; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     struct lfs_attr attrs3[] = { | ||||
|     struct lfs2_attr attrs3[] = { | ||||
|         {'A', buffer,    4}, | ||||
|         {'B', buffer+4,  9}, | ||||
|         {'C', buffer+13, 5}, | ||||
|     }; | ||||
|     struct lfs_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; | ||||
|     struct lfs2_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; | ||||
|  | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg3) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # deferred file attributes | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "hello") => 0; | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff",  9) => 0; | ||||
|     lfs_setattr(&lfs, "hello/hello", 'C', "ccccc",      5) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_setattr(&lfs2, "hello/hello", 'B', "fffffffff",  9) => 0; | ||||
|     lfs2_setattr(&lfs2, "hello/hello", 'C', "ccccc",      5) => 0; | ||||
|  | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     struct lfs_attr attrs1[] = { | ||||
|     struct lfs2_attr attrs1[] = { | ||||
|         {'B', "gggg", 4}, | ||||
|         {'C', "",     0}, | ||||
|         {'D', "hhhh", 4}, | ||||
|     }; | ||||
|     struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; | ||||
|     struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; | ||||
|  | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0; | ||||
|  | ||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; | ||||
|     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; | ||||
|     memcmp(buffer,    "fffffffff",          9) => 0; | ||||
|     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; | ||||
|     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||
|  | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     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; | ||||
|     lfs2_file_sync(&lfs2, &file) => 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; | ||||
|     memcmp(buffer,    "gggg\0\0\0\0\0",     9) => 0; | ||||
|     memcmp(buffer+9,  "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||
|     memcmp(buffer+18, "hhhh\0\0\0\0\0",     9) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -1,241 +1,241 @@ | ||||
| # bad blocks with block cycles should be tested in test_relocations | ||||
| if = 'LFS_BLOCK_CYCLES == -1' | ||||
| if = 'LFS2_BLOCK_CYCLES == -1' | ||||
|  | ||||
| [[case]] # single bad blocks | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.NAMEMULT = 64 | ||||
| define.FILEMULT = 1 | ||||
| code = ''' | ||||
|     for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { | ||||
|         lfs_testbd_setwear(&cfg, badblock-1, 0) => 0; | ||||
|         lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; | ||||
|     for (lfs2_block_t badblock = 2; badblock < LFS2_BLOCK_COUNT; badblock++) { | ||||
|         lfs2_testbd_setwear(&cfg, badblock-1, 0) => 0; | ||||
|         lfs2_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; | ||||
|          | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int i = 1; i < 10; i++) { | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j] = '0'+i; | ||||
|             } | ||||
|             buffer[NAMEMULT] = '\0'; | ||||
|             lfs_mkdir(&lfs, (char*)buffer) => 0; | ||||
|             lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|             buffer[NAMEMULT] = '/'; | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j+NAMEMULT+1] = '0'+i; | ||||
|             } | ||||
|             buffer[2*NAMEMULT+1] = '\0'; | ||||
|             lfs_file_open(&lfs, &file, (char*)buffer, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|              | ||||
|             size = NAMEMULT; | ||||
|             for (int j = 0; j < i*FILEMULT; j++) { | ||||
|                 lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|                 lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|             } | ||||
|  | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int i = 1; i < 10; i++) { | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j] = '0'+i; | ||||
|             } | ||||
|             buffer[NAMEMULT] = '\0'; | ||||
|             lfs_stat(&lfs, (char*)buffer, &info) => 0; | ||||
|             info.type => LFS_TYPE_DIR; | ||||
|             lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|             info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|             buffer[NAMEMULT] = '/'; | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j+NAMEMULT+1] = '0'+i; | ||||
|             } | ||||
|             buffer[2*NAMEMULT+1] = '\0'; | ||||
|             lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|              | ||||
|             size = NAMEMULT; | ||||
|             for (int j = 0; j < i*FILEMULT; j++) { | ||||
|                 uint8_t rbuffer[1024]; | ||||
|                 lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|                 lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|                 memcmp(buffer, rbuffer, size) => 0; | ||||
|             } | ||||
|  | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
|  | ||||
| [[case]] # region corruption (causes cascading failures) | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.NAMEMULT = 64 | ||||
| define.FILEMULT = 1 | ||||
| code = ''' | ||||
|     for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { | ||||
|         lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; | ||||
|     for (lfs2_block_t i = 0; i < (LFS2_BLOCK_COUNT-2)/2; i++) { | ||||
|         lfs2_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; | ||||
|     } | ||||
|      | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs_mkdir(&lfs, (char*)buffer) => 0; | ||||
|         lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs_file_open(&lfs, &file, (char*)buffer, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs_stat(&lfs, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS_TYPE_DIR; | ||||
|         lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             uint8_t rbuffer[1024]; | ||||
|             lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|             memcmp(buffer, rbuffer, size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # alternating corruption (causes cascading failures) | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.NAMEMULT = 64 | ||||
| define.FILEMULT = 1 | ||||
| code = ''' | ||||
|     for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { | ||||
|         lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; | ||||
|     for (lfs2_block_t i = 0; i < (LFS2_BLOCK_COUNT-2)/2; i++) { | ||||
|         lfs2_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; | ||||
|     } | ||||
|      | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs_mkdir(&lfs, (char*)buffer) => 0; | ||||
|         lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs_file_open(&lfs, &file, (char*)buffer, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs_stat(&lfs, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS_TYPE_DIR; | ||||
|         lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             uint8_t rbuffer[1024]; | ||||
|             lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|             memcmp(buffer, rbuffer, size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| # other corner cases | ||||
| [[case]] # bad superblocks (corrupt 1 or 0) | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| code = ''' | ||||
|     lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0; | ||||
|     lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0; | ||||
|     lfs2_testbd_setwear(&cfg, 0, 0xffffffff) => 0; | ||||
|     lfs2_testbd_setwear(&cfg, 1, 0xffffffff) => 0; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||
|     lfs2_format(&lfs2, &cfg) => LFS2_ERR_NOSPC; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -2,96 +2,96 @@ | ||||
| # Note that these tests are intended for 512 byte inline sizes. They should | ||||
| # still pass with other inline sizes but wouldn't be testing anything. | ||||
|  | ||||
| define.LFS_CACHE_SIZE = 512 | ||||
| if = 'LFS_CACHE_SIZE % LFS_PROG_SIZE == 0 && LFS_CACHE_SIZE == 512' | ||||
| define.LFS2_CACHE_SIZE = 512 | ||||
| if = 'LFS2_CACHE_SIZE % LFS2_PROG_SIZE == 0 && LFS2_CACHE_SIZE == 512' | ||||
|  | ||||
| [[case]] # entry grow test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry shrink test | ||||
| @@ -99,88 +99,88 @@ code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry spill test | ||||
| @@ -188,72 +188,72 @@ code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry push spill test | ||||
| @@ -261,88 +261,88 @@ code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry push spill two test | ||||
| @@ -350,103 +350,103 @@ code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi4 200 | ||||
|     sprintf(path, "hi4"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi4 200 | ||||
|     sprintf(path, "hi4"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry drop test | ||||
| @@ -454,158 +454,158 @@ code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_remove(&lfs, "hi1") => 0; | ||||
|     lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "hi1") => 0; | ||||
|     lfs2_stat(&lfs2, "hi1", &info) => LFS2_ERR_NOENT; | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_remove(&lfs, "hi2") => 0; | ||||
|     lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "hi2") => 0; | ||||
|     lfs2_stat(&lfs2, "hi2", &info) => LFS2_ERR_NOENT; | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_remove(&lfs, "hi3") => 0; | ||||
|     lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "hi3") => 0; | ||||
|     lfs2_stat(&lfs2, "hi3", &info) => LFS2_ERR_NOENT; | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_remove(&lfs, "hi0") => 0; | ||||
|     lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "hi0") => 0; | ||||
|     lfs2_stat(&lfs2, "hi0", &info) => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # create too big | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'm', 200); | ||||
|     path[200] = '\0'; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # resize too big | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'm', 200); | ||||
|     path[200] = '\0'; | ||||
|  | ||||
|     size = 40; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 40; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -4,285 +4,285 @@ | ||||
| # invalid pointer tests (outside of block_count) | ||||
|  | ||||
| [[case]] # invalid tail-pointer test | ||||
| define.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] | ||||
| define.TAIL_TYPE = ['LFS2_TYPE_HARDTAIL', 'LFS2_TYPE_SOFTTAIL'] | ||||
| define.INVALSET = [0x3, 0x1, 0x2] | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // change tail-pointer to invalid pointers | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs_block_t[2]){ | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs2_block_t[2]){ | ||||
|                     (INVALSET & 0x1) ? 0xcccccccc : 0, | ||||
|                     (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid dir pointer test | ||||
| define.INVALSET = [0x3, 0x1, 0x2] | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // make a dir | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "dir_here") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "dir_here") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // change the dir pointer to be invalid | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     // make sure id 1 == our directory | ||||
|     lfs_dir_get(&lfs, &mdir, | ||||
|             LFS_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer) | ||||
|                 => LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here")); | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("dir_here")), buffer) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_DIR, 1, strlen("dir_here")); | ||||
|     assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0); | ||||
|     // change dir pointer | ||||
|     lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8), | ||||
|                 (lfs_block_t[2]){ | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, 8), | ||||
|                 (lfs2_block_t[2]){ | ||||
|                     (INVALSET & 0x1) ? 0xcccccccc : 0, | ||||
|                     (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that accessing our bad dir fails, note there's a number | ||||
|     // of ways to access the dir, some can fail, but some don't | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "dir_here", &info) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dir_here", &info) => 0; | ||||
|     assert(strcmp(info.name, "dir_here") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|     lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT; | ||||
|     lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT; | ||||
|     lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT; | ||||
|     lfs_file_open(&lfs, &file, "dir_here/file_here", | ||||
|             LFS_O_RDONLY) => LFS_ERR_CORRUPT; | ||||
|     lfs_file_open(&lfs, &file, "dir_here/file_here", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "dir_here") => LFS2_ERR_CORRUPT; | ||||
|     lfs2_stat(&lfs2, "dir_here/file_here", &info) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "dir_here/dir_here") => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_open(&lfs2, &file, "dir_here/file_here", | ||||
|             LFS2_O_RDONLY) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_open(&lfs2, &file, "dir_here/file_here", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid file pointer test | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| define.SIZE = [10, 1000, 100000] # faked file size | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // make a file | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "file_here", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // change the file pointer to be invalid | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     // make sure id 1 == our file | ||||
|     lfs_dir_get(&lfs, &mdir, | ||||
|             LFS_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) | ||||
|                 => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here")); | ||||
|     assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); | ||||
|     // change file pointer | ||||
|     lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)), | ||||
|                 &(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz)), | ||||
|                 &(struct lfs2_ctz){0xcccccccc, lfs2_tole32(SIZE)}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that accessing our bad file fails, note there's a number | ||||
|     // of ways to access the dir, some can fail, but some don't | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "file_here", &info) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "file_here", &info) => 0; | ||||
|     assert(strcmp(info.name, "file_here") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // any allocs that traverse CTZ must unfortunately must fail | ||||
|     if (SIZE > 2*LFS_BLOCK_SIZE) { | ||||
|         lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; | ||||
|     if (SIZE > 2*LFS2_BLOCK_SIZE) { | ||||
|         lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid pointer in CTZ skip-list test | ||||
| define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE'] | ||||
| in = "lfs.c" | ||||
| define.SIZE = ['2*LFS2_BLOCK_SIZE', '3*LFS2_BLOCK_SIZE', '4*LFS2_BLOCK_SIZE'] | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // make a file | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "file_here", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         char c = 'c'; | ||||
|         lfs_file_write(&lfs, &file, &c, 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &file, &c, 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     // change pointer in CTZ skip-list to be invalid | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     // make sure id 1 == our file and get our CTZ structure | ||||
|     lfs_dir_get(&lfs, &mdir, | ||||
|             LFS_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) | ||||
|                 => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here")); | ||||
|     assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); | ||||
|     struct lfs_ctz ctz; | ||||
|     lfs_dir_get(&lfs, &mdir, | ||||
|             LFS_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz) | ||||
|                 => LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)); | ||||
|     lfs_ctz_fromle32(&ctz); | ||||
|     struct lfs2_ctz ctz; | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_STRUCT, 1, sizeof(struct lfs2_ctz)), &ctz) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz)); | ||||
|     lfs2_ctz_fromle32(&ctz); | ||||
|     // rewrite block to contain bad pointer | ||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|     uint32_t bad = lfs_tole32(0xcccccccc); | ||||
|     uint8_t bbuffer[LFS2_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, ctz.head, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     uint32_t bad = lfs2_tole32(0xcccccccc); | ||||
|     memcpy(&bbuffer[0], &bad, sizeof(bad)); | ||||
|     memcpy(&bbuffer[4], &bad, sizeof(bad)); | ||||
|     cfg.erase(&cfg, ctz.head) => 0; | ||||
|     cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that accessing our bad file fails, note there's a number | ||||
|     // of ways to access the dir, some can fail, but some don't | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "file_here", &info) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "file_here", &info) => 0; | ||||
|     assert(strcmp(info.name, "file_here") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // any allocs that traverse CTZ must unfortunately must fail | ||||
|     if (SIZE > 2*LFS_BLOCK_SIZE) { | ||||
|         lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; | ||||
|     if (SIZE > 2*LFS2_BLOCK_SIZE) { | ||||
|         lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
|  | ||||
| [[case]] # invalid gstate pointer | ||||
| define.INVALSET = [0x3, 0x1, 0x2] | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // create an invalid gstate | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_fs_prepmove(&lfs2, 1, (lfs2_block_t [2]){ | ||||
|             (INVALSET & 0x1) ? 0xcccccccc : 0, | ||||
|             (INVALSET & 0x2) ? 0xcccccccc : 0}); | ||||
|     lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, NULL, 0) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     // mount may not fail, but our first alloc should fail when | ||||
|     // we try to fix the gstate | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "should_fail") => LFS2_ERR_CORRUPT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| # cycle detection/recovery tests | ||||
|  | ||||
| [[case]] # metadata-pair threaded-list loop test | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // change tail-pointer to point to ourself | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs_block_t[2]){0, 1}})) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs2_block_t[2]){0, 1}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # metadata-pair threaded-list 2-length loop test | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs with child dir | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "child") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // find child | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_block_t pair[2]; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs_dir_get(&lfs, &mdir, | ||||
|             LFS_MKTAG(0x7ff, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) | ||||
|                 => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); | ||||
|     lfs_pair_fromle32(pair); | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_block_t pair[2]; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x7ff, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)); | ||||
|     lfs2_pair_fromle32(pair); | ||||
|     // change tail-pointer to point to root | ||||
|     lfs_dir_fetch(&lfs, &mdir, pair) => 0; | ||||
|     lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs_block_t[2]){0, 1}})) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, pair) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs2_block_t[2]){0, 1}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # metadata-pair threaded-list 1-length child loop test | ||||
| in = "lfs.c" | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs with child dir | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "child") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // find child | ||||
|     lfs_init(&lfs, &cfg) => 0; | ||||
|     lfs_mdir_t mdir; | ||||
|     lfs_block_t pair[2]; | ||||
|     lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; | ||||
|     lfs_dir_get(&lfs, &mdir, | ||||
|             LFS_MKTAG(0x7ff, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) | ||||
|                 => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); | ||||
|     lfs_pair_fromle32(pair); | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_block_t pair[2]; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x7ff, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)); | ||||
|     lfs2_pair_fromle32(pair); | ||||
|     // change tail-pointer to point to ourself | ||||
|     lfs_dir_fetch(&lfs, &mdir, pair) => 0; | ||||
|     lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0; | ||||
|     lfs_deinit(&lfs) => 0; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, pair) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|   | ||||
| @@ -1,49 +1,49 @@ | ||||
| [[case]] # test running a filesystem to exhaustion | ||||
| define.LFS_ERASE_CYCLES = 10 | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' | ||||
| define.LFS_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||
| define.LFS2_ERASE_CYCLES = 10 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "roadrunner") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "roadrunner") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (true) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
|                 if (res == LFS_ERR_NOSPC) { | ||||
|                     err = lfs_file_close(&lfs, &file); | ||||
|                     assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                     lfs_unmount(&lfs) => 0; | ||||
|                 lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                 if (res == LFS2_ERR_NOSPC) { | ||||
|                     err = lfs2_file_close(&lfs2, &file); | ||||
|                     assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs_file_close(&lfs, &file); | ||||
|             assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|             if (err == LFS_ERR_NOSPC) { | ||||
|                 lfs_unmount(&lfs) => 0; | ||||
|             err = lfs2_file_close(&lfs2, &file); | ||||
|             assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|             if (err == LFS2_ERR_NOSPC) { | ||||
|                 lfs2_unmount(&lfs2) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
| @@ -54,78 +54,78 @@ code = ''' | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
|                 lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "roadrunner/test%d", i); | ||||
|         lfs_stat(&lfs, path, &info) => 0; | ||||
|         lfs2_stat(&lfs2, path, &info) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     LFS_WARN("completed %d cycles", cycle); | ||||
|     LFS2_WARN("completed %d cycles", cycle); | ||||
| ''' | ||||
|  | ||||
| [[case]] # test running a filesystem to exhaustion | ||||
|          # which also requires expanding superblocks | ||||
| define.LFS_ERASE_CYCLES = 10 | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' | ||||
| define.LFS_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS_TESTBD_BADBLOCK_ERASENOOP', | ||||
| define.LFS2_ERASE_CYCLES = 10 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (true) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
|                 if (res == LFS_ERR_NOSPC) { | ||||
|                     err = lfs_file_close(&lfs, &file); | ||||
|                     assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                     lfs_unmount(&lfs) => 0; | ||||
|                 lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                 if (res == LFS2_ERR_NOSPC) { | ||||
|                     err = lfs2_file_close(&lfs2, &file); | ||||
|                     assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs_file_close(&lfs, &file); | ||||
|             assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|             if (err == LFS_ERR_NOSPC) { | ||||
|                 lfs_unmount(&lfs) => 0; | ||||
|             err = lfs2_file_close(&lfs2, &file); | ||||
|             assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|             if (err == LFS2_ERR_NOSPC) { | ||||
|                 lfs2_unmount(&lfs2) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
| @@ -136,32 +136,32 @@ code = ''' | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
|                 lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "test%d", i); | ||||
|         lfs_stat(&lfs, path, &info) => 0; | ||||
|         lfs2_stat(&lfs2, path, &info) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     LFS_WARN("completed %d cycles", cycle); | ||||
|     LFS2_WARN("completed %d cycles", cycle); | ||||
| ''' | ||||
|  | ||||
| # These are a sort of high-level litmus test for wear-leveling. One definition | ||||
| @@ -170,53 +170,53 @@ exhausted: | ||||
| # check for. | ||||
|  | ||||
| [[case]] # wear-level test running a filesystem to exhaustion | ||||
| define.LFS_ERASE_CYCLES = 20 | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' | ||||
| define.LFS2_ERASE_CYCLES = 20 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     uint32_t run_cycles[2]; | ||||
|     const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; | ||||
|     const uint32_t run_block_count[2] = {LFS2_BLOCK_COUNT/2, LFS2_BLOCK_COUNT}; | ||||
|  | ||||
|     for (int run = 0; run < 2; run++) { | ||||
|         for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { | ||||
|             lfs_testbd_setwear(&cfg, b, | ||||
|                     (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; | ||||
|         for (lfs2_block_t b = 0; b < LFS2_BLOCK_COUNT; b++) { | ||||
|             lfs2_testbd_setwear(&cfg, b, | ||||
|                     (b < run_block_count[run]) ? 0 : LFS2_ERASE_CYCLES) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs_mkdir(&lfs, "roadrunner") => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_mkdir(&lfs2, "roadrunner") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         uint32_t cycle = 0; | ||||
|         while (true) { | ||||
|             lfs_mount(&lfs, &cfg) => 0; | ||||
|             lfs2_mount(&lfs2, &cfg) => 0; | ||||
|             for (uint32_t i = 0; i < FILES; i++) { | ||||
|                 // chose name, roughly random seed, and random 2^n size | ||||
|                 sprintf(path, "roadrunner/test%d", i); | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs_file_open(&lfs, &file, path, | ||||
|                         LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|                 lfs2_file_open(&lfs2, &file, path, | ||||
|                         LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|                 for (lfs_size_t j = 0; j < size; j++) { | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
|                     assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
|                     if (res == LFS_ERR_NOSPC) { | ||||
|                         err = lfs_file_close(&lfs, &file); | ||||
|                         assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                         lfs_unmount(&lfs) => 0; | ||||
|                     lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                     assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                     if (res == LFS2_ERR_NOSPC) { | ||||
|                         err = lfs2_file_close(&lfs2, &file); | ||||
|                         assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                         lfs2_unmount(&lfs2) => 0; | ||||
|                         goto exhausted; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 err = lfs_file_close(&lfs, &file); | ||||
|                 assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                 if (err == LFS_ERR_NOSPC) { | ||||
|                     lfs_unmount(&lfs) => 0; | ||||
|                 err = lfs2_file_close(&lfs2, &file); | ||||
|                 assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                 if (err == LFS2_ERR_NOSPC) { | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
| @@ -227,85 +227,85 @@ code = ''' | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|                 for (lfs_size_t j = 0; j < size; j++) { | ||||
|                 lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     char r; | ||||
|                     lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
|                     lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                     assert(r == c); | ||||
|                 } | ||||
|  | ||||
|                 lfs_file_close(&lfs, &file) => 0; | ||||
|                 lfs2_file_close(&lfs2, &file) => 0; | ||||
|             } | ||||
|             lfs_unmount(&lfs) => 0; | ||||
|             lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|             cycle += 1; | ||||
|         } | ||||
|  | ||||
| exhausted: | ||||
|         // should still be readable | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             lfs_stat(&lfs, path, &info) => 0; | ||||
|             lfs2_stat(&lfs2, path, &info) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         run_cycles[run] = cycle; | ||||
|         LFS_WARN("completed %d blocks %d cycles", | ||||
|         LFS2_WARN("completed %d blocks %d cycles", | ||||
|                 run_block_count[run], run_cycles[run]); | ||||
|     } | ||||
|  | ||||
|     // check we increased the lifetime by 2x with ~10% error | ||||
|     LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
|     LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
| ''' | ||||
|  | ||||
| [[case]] # wear-level test + expanding superblock | ||||
| define.LFS_ERASE_CYCLES = 20 | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' | ||||
| define.LFS2_ERASE_CYCLES = 20 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     uint32_t run_cycles[2]; | ||||
|     const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; | ||||
|     const uint32_t run_block_count[2] = {LFS2_BLOCK_COUNT/2, LFS2_BLOCK_COUNT}; | ||||
|  | ||||
|     for (int run = 0; run < 2; run++) { | ||||
|         for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { | ||||
|             lfs_testbd_setwear(&cfg, b, | ||||
|                     (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; | ||||
|         for (lfs2_block_t b = 0; b < LFS2_BLOCK_COUNT; b++) { | ||||
|             lfs2_testbd_setwear(&cfg, b, | ||||
|                     (b < run_block_count[run]) ? 0 : LFS2_ERASE_CYCLES) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|         uint32_t cycle = 0; | ||||
|         while (true) { | ||||
|             lfs_mount(&lfs, &cfg) => 0; | ||||
|             lfs2_mount(&lfs2, &cfg) => 0; | ||||
|             for (uint32_t i = 0; i < FILES; i++) { | ||||
|                 // chose name, roughly random seed, and random 2^n size | ||||
|                 sprintf(path, "test%d", i); | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs_file_open(&lfs, &file, path, | ||||
|                         LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|                 lfs2_file_open(&lfs2, &file, path, | ||||
|                         LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|                 for (lfs_size_t j = 0; j < size; j++) { | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
|                     assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
|                     if (res == LFS_ERR_NOSPC) { | ||||
|                         err = lfs_file_close(&lfs, &file); | ||||
|                         assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                         lfs_unmount(&lfs) => 0; | ||||
|                     lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                     assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                     if (res == LFS2_ERR_NOSPC) { | ||||
|                         err = lfs2_file_close(&lfs2, &file); | ||||
|                         assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                         lfs2_unmount(&lfs2) => 0; | ||||
|                         goto exhausted; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 err = lfs_file_close(&lfs, &file); | ||||
|                 assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                 if (err == LFS_ERR_NOSPC) { | ||||
|                     lfs_unmount(&lfs) => 0; | ||||
|                 err = lfs2_file_close(&lfs2, &file); | ||||
|                 assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                 if (err == LFS2_ERR_NOSPC) { | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
| @@ -316,81 +316,81 @@ code = ''' | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|                 for (lfs_size_t j = 0; j < size; j++) { | ||||
|                 lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     char r; | ||||
|                     lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
|                     lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                     assert(r == c); | ||||
|                 } | ||||
|  | ||||
|                 lfs_file_close(&lfs, &file) => 0; | ||||
|                 lfs2_file_close(&lfs2, &file) => 0; | ||||
|             } | ||||
|             lfs_unmount(&lfs) => 0; | ||||
|             lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|             cycle += 1; | ||||
|         } | ||||
|  | ||||
| exhausted: | ||||
|         // should still be readable | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "test%d", i); | ||||
|             lfs_stat(&lfs, path, &info) => 0; | ||||
|             lfs2_stat(&lfs2, path, &info) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         run_cycles[run] = cycle; | ||||
|         LFS_WARN("completed %d blocks %d cycles", | ||||
|         LFS2_WARN("completed %d blocks %d cycles", | ||||
|                 run_block_count[run], run_cycles[run]); | ||||
|     } | ||||
|  | ||||
|     // check we increased the lifetime by 2x with ~10% error | ||||
|     LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
|     LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
| ''' | ||||
|  | ||||
| [[case]] # test that we wear blocks roughly evenly | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1] | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = [5, 4, 3, 2, 1] | ||||
| define.CYCLES = 100 | ||||
| define.FILES = 10 | ||||
| if = 'LFS_BLOCK_CYCLES < CYCLES/10' | ||||
| if = 'LFS2_BLOCK_CYCLES < CYCLES/10' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "roadrunner") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "roadrunner") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (cycle < CYCLES) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << 4; //((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
|                 if (res == LFS_ERR_NOSPC) { | ||||
|                     err = lfs_file_close(&lfs, &file); | ||||
|                     assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                     lfs_unmount(&lfs) => 0; | ||||
|                 lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                 if (res == LFS2_ERR_NOSPC) { | ||||
|                     err = lfs2_file_close(&lfs2, &file); | ||||
|                     assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs_file_close(&lfs, &file); | ||||
|             assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|             if (err == LFS_ERR_NOSPC) { | ||||
|                 lfs_unmount(&lfs) => 0; | ||||
|             err = lfs2_file_close(&lfs2, &file); | ||||
|             assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|             if (err == LFS2_ERR_NOSPC) { | ||||
|                 lfs2_unmount(&lfs2) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
| @@ -401,40 +401,40 @@ code = ''' | ||||
|             srand(cycle * i); | ||||
|             size = 1 << 4; //((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
|                 lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "roadrunner/test%d", i); | ||||
|         lfs_stat(&lfs, path, &info) => 0; | ||||
|         lfs2_stat(&lfs2, path, &info) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     LFS_WARN("completed %d cycles", cycle); | ||||
|     LFS2_WARN("completed %d cycles", cycle); | ||||
|  | ||||
|     // check the wear on our block device | ||||
|     lfs_testbd_wear_t minwear = -1; | ||||
|     lfs_testbd_wear_t totalwear = 0; | ||||
|     lfs_testbd_wear_t maxwear = 0; | ||||
|     lfs2_testbd_wear_t minwear = -1; | ||||
|     lfs2_testbd_wear_t totalwear = 0; | ||||
|     lfs2_testbd_wear_t maxwear = 0; | ||||
|     // skip 0 and 1 as superblock movement is intentionally avoided | ||||
|     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||
|         lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); | ||||
|     for (lfs2_block_t b = 2; b < LFS2_BLOCK_COUNT; b++) { | ||||
|         lfs2_testbd_wear_t wear = lfs2_testbd_getwear(&cfg, b); | ||||
|         printf("%08x: wear %d\n", b, wear); | ||||
|         assert(wear >= 0); | ||||
|         if (wear < minwear) { | ||||
| @@ -445,21 +445,21 @@ exhausted: | ||||
|         } | ||||
|         totalwear += wear; | ||||
|     } | ||||
|     lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT; | ||||
|     LFS_WARN("max wear: %d cycles", maxwear); | ||||
|     LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT); | ||||
|     LFS_WARN("min wear: %d cycles", minwear); | ||||
|     lfs2_testbd_wear_t avgwear = totalwear / LFS2_BLOCK_COUNT; | ||||
|     LFS2_WARN("max wear: %d cycles", maxwear); | ||||
|     LFS2_WARN("avg wear: %d cycles", totalwear / LFS2_BLOCK_COUNT); | ||||
|     LFS2_WARN("min wear: %d cycles", minwear); | ||||
|  | ||||
|     // find standard deviation^2 | ||||
|     lfs_testbd_wear_t dev2 = 0; | ||||
|     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||
|         lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); | ||||
|     lfs2_testbd_wear_t dev2 = 0; | ||||
|     for (lfs2_block_t b = 2; b < LFS2_BLOCK_COUNT; b++) { | ||||
|         lfs2_testbd_wear_t wear = lfs2_testbd_getwear(&cfg, b); | ||||
|         assert(wear >= 0); | ||||
|         lfs_testbd_swear_t diff = wear - avgwear; | ||||
|         lfs2_testbd_swear_t diff = wear - avgwear; | ||||
|         dev2 += diff*diff; | ||||
|     } | ||||
|     dev2 /= totalwear; | ||||
|     LFS_WARN("std dev^2: %d", dev2); | ||||
|     LFS2_WARN("std dev^2: %d", dev2); | ||||
|     assert(dev2 < 8); | ||||
| ''' | ||||
|  | ||||
|   | ||||
| @@ -1,60 +1,60 @@ | ||||
|  | ||||
| [[case]] # simple file test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "hello", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     size = strlen("Hello World!")+1; | ||||
|     strcpy((char*)buffer, "Hello World!"); | ||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     assert(strcmp((char*)buffer, "Hello World!") == 0); | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # larger files | ||||
| define.SIZE = [32, 8192, 262144, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 33, 1, 1023] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # rewriting files | ||||
| @@ -62,81 +62,81 @@ define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 1] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE1; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // rewrite | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY) => 0; | ||||
|     srand(2); | ||||
|     for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => lfs2_max(SIZE1, SIZE2); | ||||
|     srand(2); | ||||
|     for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     if (SIZE1 > SIZE2) { | ||||
|         srand(1); | ||||
|         for (lfs_size_t b = 0; b < SIZE2; b++) { | ||||
|         for (lfs2_size_t b = 0; b < SIZE2; b++) { | ||||
|             rand(); | ||||
|         } | ||||
|         for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { | ||||
|             lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|             lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|             for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|         for (lfs2_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { | ||||
|             lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|             lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|             for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|                 assert(buffer[b] == (rand() & 0xff)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # appending files | ||||
| @@ -144,76 +144,76 @@ define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 1] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE1; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // append | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_APPEND) => 0; | ||||
|     srand(2); | ||||
|     for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1 + SIZE2; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     srand(2); | ||||
|     for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncating files | ||||
| @@ -221,68 +221,68 @@ define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 1] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE1; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // truncate | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; | ||||
|     srand(2); | ||||
|     for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE2; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE2; | ||||
|     srand(2); | ||||
|     for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant file writing | ||||
| @@ -290,197 +290,197 @@ define.SIZE = [32, 0, 7, 2049] | ||||
| define.CHUNKSIZE = [31, 16, 65] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); | ||||
|     assert(err == LFS_ERR_NOENT || err == 0); | ||||
|     err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY); | ||||
|     assert(err == LFS2_ERR_NOENT || err == 0); | ||||
|     if (err == 0) { | ||||
|         // can only be 0 (new file) or full size | ||||
|         size = lfs_file_size(&lfs, &file); | ||||
|         size = lfs2_file_size(&lfs2, &file); | ||||
|         assert(size == 0 || size == SIZE); | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     // write | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant file writing with syncs | ||||
| define = [ | ||||
|     # append (O(n)) | ||||
|     {MODE='LFS_O_APPEND',   SIZE=[32, 0, 7, 2049],  CHUNKSIZE=[31, 16, 65]}, | ||||
|     {MODE='LFS2_O_APPEND',   SIZE=[32, 0, 7, 2049],  CHUNKSIZE=[31, 16, 65]}, | ||||
|     # truncate (O(n^2)) | ||||
|     {MODE='LFS_O_TRUNC',    SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]}, | ||||
|     {MODE='LFS2_O_TRUNC',    SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]}, | ||||
|     # rewrite (O(n^2)) | ||||
|     {MODE=0,                SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]}, | ||||
| ] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); | ||||
|     assert(err == LFS_ERR_NOENT || err == 0); | ||||
|     err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY); | ||||
|     assert(err == LFS2_ERR_NOENT || err == 0); | ||||
|     if (err == 0) { | ||||
|         // with syncs we could be any size, but it at least must be valid data | ||||
|         size = lfs_file_size(&lfs, &file); | ||||
|         size = lfs2_file_size(&lfs2, &file); | ||||
|         assert(size <= SIZE); | ||||
|         srand(1); | ||||
|         for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { | ||||
|             lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i); | ||||
|             lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|             for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|         for (lfs2_size_t i = 0; i < size; i += CHUNKSIZE) { | ||||
|             lfs2_size_t chunk = lfs2_min(CHUNKSIZE, size-i); | ||||
|             lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|             for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|                 assert(buffer[b] == (rand() & 0xff)); | ||||
|             } | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     // write | ||||
|     lfs_file_open(&lfs, &file, "avacado", | ||||
|         LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; | ||||
|     size = lfs_file_size(&lfs, &file); | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|         LFS2_O_WRONLY | LFS2_O_CREAT | MODE) => 0; | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     assert(size <= SIZE); | ||||
|     srand(1); | ||||
|     lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; | ||||
|     for (lfs_size_t b = 0; b < skip; b++) { | ||||
|     lfs2_size_t skip = (MODE == LFS2_O_APPEND) ? size : 0; | ||||
|     for (lfs2_size_t b = 0; b < skip; b++) { | ||||
|         rand(); | ||||
|     } | ||||
|     for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = skip; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     srand(1); | ||||
|     for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; | ||||
|         for (lfs_size_t b = 0; b < chunk; b++) { | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many files | ||||
| define.N = 300 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // create N files of 7 bytes | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs_file_open(&lfs, &file, path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         char wbuffer[1024]; | ||||
|         size = 7; | ||||
|         snprintf(wbuffer, size, "Hi %03d", i); | ||||
|         lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|         char rbuffer[1024]; | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(strcmp(rbuffer, wbuffer) == 0); | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many files with power cycle | ||||
| define.N = 300 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // create N files of 7 bytes | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs_file_open(&lfs, &file, path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         char wbuffer[1024]; | ||||
|         size = 7; | ||||
|         snprintf(wbuffer, size, "Hi %03d", i); | ||||
|         lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         char rbuffer[1024]; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(strcmp(rbuffer, wbuffer) == 0); | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many files with power loss | ||||
| define.N = 300 | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     // create N files of 7 bytes | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); | ||||
|         err = lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|         char wbuffer[1024]; | ||||
|         size = 7; | ||||
|         snprintf(wbuffer, size, "Hi %03d", i); | ||||
|         if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { | ||||
|             lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||
|         if ((lfs2_size_t)lfs2_file_size(&lfs2, &file) != size) { | ||||
|             lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|         char rbuffer[1024]; | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(strcmp(rbuffer, wbuffer) == 0); | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -3,60 +3,60 @@ | ||||
| define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26]  | ||||
| code = ''' | ||||
|     lfs_file_t files[FILES]; | ||||
|     lfs2_file_t files[FILES]; | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_file_open(&lfs, &files[j], path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs2_file_open(&lfs2, &files[j], path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; | ||||
|             lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_close(&lfs, &files[j]); | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|  | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS_TYPE_REG); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(info.size == SIZE); | ||||
|     } | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; | ||||
|         lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             lfs_file_read(&lfs, &files[j], buffer, 1) => 1; | ||||
|             lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_close(&lfs, &files[j]); | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|      | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # interspersed remove file test | ||||
| @@ -64,112 +64,112 @@ define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_file_open(&lfs, &file, path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         for (int i = 0; i < SIZE; i++) { | ||||
|             lfs_file_write(&lfs, &file, &alphas[j], 1) => 1; | ||||
|             lfs2_file_write(&lfs2, &file, &alphas[j], 1) => 1; | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file); | ||||
|         lfs2_file_close(&lfs2, &file); | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|         lfs2_file_write(&lfs2, &file, (const void*)"~", 1) => 1; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_remove(&lfs, path) => 0; | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|  | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "zzz") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == FILES); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < FILES; i++) { | ||||
|         lfs_file_read(&lfs, &file, buffer, 1) => 1; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, 1) => 1; | ||||
|         assert(buffer[0] == '~'); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|      | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # remove inconveniently test | ||||
| define.SIZE = [10, 100] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t files[3]; | ||||
|     lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_t files[3]; | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "f", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[2], "g", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     for (int i = 0; i < SIZE/2; i++) { | ||||
|         lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs_remove(&lfs, "f") => 0; | ||||
|     lfs2_remove(&lfs2, "f") => 0; | ||||
|  | ||||
|     for (int i = 0; i < SIZE/2; i++) { | ||||
|         lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs_file_close(&lfs, &files[0]); | ||||
|     lfs_file_close(&lfs, &files[1]); | ||||
|     lfs_file_close(&lfs, &files[2]); | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|     lfs2_file_close(&lfs2, &files[2]); | ||||
|  | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "e") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "g") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "g", LFS2_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         lfs_file_read(&lfs, &files[0], buffer, 1) => 1; | ||||
|         lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1; | ||||
|         assert(buffer[0] == 'e'); | ||||
|         lfs_file_read(&lfs, &files[1], buffer, 1) => 1; | ||||
|         lfs2_file_read(&lfs2, &files[1], buffer, 1) => 1; | ||||
|         assert(buffer[0] == 'g'); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &files[0]); | ||||
|     lfs_file_close(&lfs, &files[1]); | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|      | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant interspersed file test | ||||
| @@ -177,68 +177,68 @@ define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26]  | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     lfs_file_t files[FILES]; | ||||
|     lfs2_file_t files[FILES]; | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|  | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_file_open(&lfs, &files[j], path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|         lfs2_file_open(&lfs2, &files[j], path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             size = lfs_file_size(&lfs, &files[j]); | ||||
|             size = lfs2_file_size(&lfs2, &files[j]); | ||||
|             assert((int)size >= 0); | ||||
|             if ((int)size <= i) { | ||||
|                 lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; | ||||
|                 lfs_file_sync(&lfs, &files[j]) => 0; | ||||
|                 lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1; | ||||
|                 lfs2_file_sync(&lfs2, &files[j]) => 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_close(&lfs, &files[j]); | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|  | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS_TYPE_REG); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(info.size == SIZE); | ||||
|     } | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; | ||||
|         lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             lfs_file_read(&lfs, &files[j], buffer, 1) => 1; | ||||
|             lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_close(&lfs, &files[j]); | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|      | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
							
								
								
									
										2448
									
								
								tests/test_move.toml
									
									
									
									
									
								
							
							
						
						
									
										2448
									
								
								tests/test_move.toml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,75 +1,75 @@ | ||||
| [[case]] # orphan test | ||||
| in = "lfs.c" | ||||
| if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit | ||||
| in = "lfs2.c" | ||||
| if = 'LFS2_PROG_SIZE <= 0x3fe' # only works with one crc per commit | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 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; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     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; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // corrupt the child's most recent commit, this should be the update | ||||
|     // to the linked-list entry, which should orphan the orphan. Note this | ||||
|     // makes a lot of assumptions about the remove operation. | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir, "parent/child") => 0; | ||||
|     lfs_block_t block = dir.m.pair[0]; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|     int off = LFS_BLOCK_SIZE-1; | ||||
|     while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "parent/child") => 0; | ||||
|     lfs2_block_t block = dir.m.pair[0]; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     uint8_t bbuffer[LFS2_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     int off = LFS2_BLOCK_SIZE-1; | ||||
|     while (off >= 0 && bbuffer[off] == LFS2_ERASE_VALUE) { | ||||
|         off -= 1; | ||||
|     } | ||||
|     memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); | ||||
|     memset(&bbuffer[off-3], LFS2_BLOCK_SIZE, 3); | ||||
|     cfg.erase(&cfg, block) => 0; | ||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     cfg.sync(&cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; | ||||
|     lfs_stat(&lfs, "parent/child", &info) => 0; | ||||
|     lfs_fs_size(&lfs) => 8; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; | ||||
|     lfs_stat(&lfs, "parent/child", &info) => 0; | ||||
|     lfs_fs_size(&lfs) => 8; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     // this mkdir should both create a dir and deorphan, so size | ||||
|     // should be unchanged | ||||
|     lfs_mkdir(&lfs, "parent/otherchild") => 0; | ||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; | ||||
|     lfs_stat(&lfs, "parent/child", &info) => 0; | ||||
|     lfs_stat(&lfs, "parent/otherchild", &info) => 0; | ||||
|     lfs_fs_size(&lfs) => 8; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent/otherchild") => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/otherchild", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; | ||||
|     lfs_stat(&lfs, "parent/child", &info) => 0; | ||||
|     lfs_stat(&lfs, "parent/otherchild", &info) => 0; | ||||
|     lfs_fs_size(&lfs) => 8; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/otherchild", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for orphans, basically just spam mkdir/remove | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| if = '!(DEPTH == 3 && LFS2_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20}, | ||||
| ] | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     srand(1); | ||||
| @@ -82,39 +82,39 @@ code = ''' | ||||
|         } | ||||
|  | ||||
|         // if it does not exist, we create it, else we destroy | ||||
|         int res = lfs_stat(&lfs, full_path, &info); | ||||
|         if (res == LFS_ERR_NOENT) { | ||||
|         int res = lfs2_stat(&lfs2, full_path, &info); | ||||
|         if (res == LFS2_ERR_NOENT) { | ||||
|             // create each directory in turn, ignore if dir already exists | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs_mkdir(&lfs, path); | ||||
|                 assert(!err || err == LFS_ERR_EXIST); | ||||
|                 err = lfs2_mkdir(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_EXIST); | ||||
|             } | ||||
|  | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 lfs_stat(&lfs, path, &info) => 0; | ||||
|                 lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                 assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                 assert(info.type == LFS_TYPE_DIR); | ||||
|                 assert(info.type == LFS2_TYPE_DIR); | ||||
|             } | ||||
|         } else { | ||||
|             // is valid dir? | ||||
|             assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); | ||||
|             assert(info.type == LFS_TYPE_DIR); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|             // try to delete path in reverse order, ignore if dir is not empty | ||||
|             for (int d = DEPTH-1; d >= 0; d--) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs_remove(&lfs, path); | ||||
|                 assert(!err || err == LFS_ERR_NOTEMPTY); | ||||
|                 err = lfs2_remove(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|             } | ||||
|  | ||||
|             lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; | ||||
|             lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|         } | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
|   | ||||
| @@ -1,293 +1,293 @@ | ||||
|  | ||||
| [[case]] # simple path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "/tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs_mkdir(&lfs, "/milk") => 0; | ||||
|     lfs_stat(&lfs, "/milk", &info) => 0; | ||||
|     lfs2_mkdir(&lfs2, "/milk") => 0; | ||||
|     lfs2_stat(&lfs2, "/milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # redundant slashes | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "/tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "//tea//hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "//tea//hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "///tea///hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "///tea///hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs_mkdir(&lfs, "////milk") => 0; | ||||
|     lfs_stat(&lfs, "////milk", &info) => 0; | ||||
|     lfs2_mkdir(&lfs2, "////milk") => 0; | ||||
|     lfs2_stat(&lfs2, "////milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # dot path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "./tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "./tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "/./tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "/./tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "/././tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "/././tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "/./tea/./hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs_mkdir(&lfs, "/./milk") => 0; | ||||
|     lfs_stat(&lfs, "/./milk", &info) => 0; | ||||
|     lfs2_mkdir(&lfs2, "/./milk") => 0; | ||||
|     lfs2_stat(&lfs2, "/./milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # dot dot path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/coldtea/../hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/coldcoffee/../../tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "coffee/../coffee/../tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../coffee/../tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs_mkdir(&lfs, "coffee/../milk") => 0; | ||||
|     lfs_stat(&lfs, "coffee/../milk", &info) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/../milk") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # trailing dot path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "tea/hottea/", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "tea/hottea/.", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/.", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/./.", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs_stat(&lfs, "tea/hottea/..", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/..", &info) => 0; | ||||
|     assert(strcmp(info.name, "tea") == 0); | ||||
|     lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/../.", &info) => 0; | ||||
|     assert(strcmp(info.name, "tea") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # leading dot path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, ".milk") => 0; | ||||
|     lfs_stat(&lfs, ".milk", &info) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, ".milk") => 0; | ||||
|     lfs2_stat(&lfs2, ".milk", &info) => 0; | ||||
|     strcmp(info.name, ".milk") => 0; | ||||
|     lfs_stat(&lfs, "tea/.././.milk", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/.././.milk", &info) => 0; | ||||
|     strcmp(info.name, ".milk") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # root dot dot path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; | ||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0; | ||||
|     lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/../../../../../../milk") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../../../../../../milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid path tests | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg); | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; | ||||
|     lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; | ||||
|     lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; | ||||
|     lfs2_format(&lfs2, &cfg); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dirt", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "dirt/ground", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "dirt/ground/earth", &info) => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs_remove(&lfs, "dirt") => LFS_ERR_NOENT; | ||||
|     lfs_remove(&lfs, "dirt/ground") => LFS_ERR_NOENT; | ||||
|     lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "dirt") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "dirt/ground") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; | ||||
|     lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) | ||||
|             => LFS_ERR_NOENT; | ||||
|     lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; | ||||
|     lfs_file_open(&lfs, &file, "dirt/ground/earth", LFS_O_WRONLY | LFS_O_CREAT) | ||||
|             => LFS_ERR_NOENT; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mkdir(&lfs2, "dirt/ground") => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "dirt/ground", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NOENT; | ||||
|     lfs2_mkdir(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "dirt/ground/earth", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # root operations | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "/", &info) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "/", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|     lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; | ||||
|     lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) | ||||
|             => LFS_ERR_ISDIR; | ||||
|     lfs2_mkdir(&lfs2, "/") => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "/", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_ISDIR; | ||||
|  | ||||
|     lfs_remove(&lfs, "/") => LFS_ERR_INVAL; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_remove(&lfs2, "/") => LFS2_ERR_INVAL; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # root representations | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "/", &info) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "/", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_stat(&lfs, "", &info) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_stat(&lfs, ".", &info) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, ".", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_stat(&lfs, "..", &info) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "..", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_stat(&lfs, "//", &info) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "//", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_stat(&lfs, "./", &info) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "./", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # superblock conflict test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; | ||||
|     lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "littlefs", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "littlefs") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs_mkdir(&lfs, "littlefs") => 0; | ||||
|     lfs_stat(&lfs, "littlefs", &info) => 0; | ||||
|     lfs2_mkdir(&lfs2, "littlefs") => 0; | ||||
|     lfs2_stat(&lfs2, "littlefs", &info) => 0; | ||||
|     assert(strcmp(info.name, "littlefs") == 0); | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     lfs_remove(&lfs, "littlefs") => 0; | ||||
|     lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_remove(&lfs2, "littlefs") => 0; | ||||
|     lfs2_stat(&lfs2, "littlefs", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # max path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "coffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     memset(path, 'w', LFS_NAME_MAX+1); | ||||
|     path[LFS_NAME_MAX+1] = '\0'; | ||||
|     lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) | ||||
|             => LFS_ERR_NAMETOOLONG; | ||||
|     memset(path, 'w', LFS2_NAME_MAX+1); | ||||
|     path[LFS2_NAME_MAX+1] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NAMETOOLONG; | ||||
|  | ||||
|     memcpy(path, "coffee/", strlen("coffee/")); | ||||
|     memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); | ||||
|     path[strlen("coffee/")+LFS_NAME_MAX+1] = '\0'; | ||||
|     lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; | ||||
|     lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) | ||||
|             => LFS_ERR_NAMETOOLONG; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX+1); | ||||
|     path[strlen("coffee/")+LFS2_NAME_MAX+1] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # really big path test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "coffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     memset(path, 'w', LFS_NAME_MAX); | ||||
|     path[LFS_NAME_MAX] = '\0'; | ||||
|     lfs_mkdir(&lfs, path) => 0; | ||||
|     lfs_remove(&lfs, path) => 0; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_remove(&lfs, path) => 0; | ||||
|     memset(path, 'w', LFS2_NAME_MAX); | ||||
|     path[LFS2_NAME_MAX] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|  | ||||
|     memcpy(path, "coffee/", strlen("coffee/")); | ||||
|     memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX); | ||||
|     path[strlen("coffee/")+LFS_NAME_MAX] = '\0'; | ||||
|     lfs_mkdir(&lfs, path) => 0; | ||||
|     lfs_remove(&lfs, path) => 0; | ||||
|     lfs_file_open(&lfs, &file, path, | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_remove(&lfs, path) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX); | ||||
|     path[strlen("coffee/")+LFS2_NAME_MAX] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
|   | ||||
| @@ -2,39 +2,39 @@ | ||||
| [[case]] # dangling split dir test | ||||
| define.ITERATIONS = 20 | ||||
| define.COUNT = 10 | ||||
| define.LFS_BLOCK_CYCLES = [8, 1] | ||||
| define.LFS2_BLOCK_CYCLES = [8, 1] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // fill up filesystem so only ~16 blocks are left | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     memset(buffer, 0, 512); | ||||
|     while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { | ||||
|         lfs_file_write(&lfs, &file, buffer, 512) => 512; | ||||
|     while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, 512) => 512; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // make a child dir to use in bounded space | ||||
|     lfs_mkdir(&lfs, "child") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < ITERATIONS; j++) { | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_dir_open(&lfs, &dir, "child") => 0; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|         } | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|         lfs_dir_close(&lfs, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         if (j == ITERATIONS-1) { | ||||
|             break; | ||||
| @@ -42,105 +42,105 @@ code = ''' | ||||
|  | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_remove(&lfs, path) => 0; | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir, "child") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|     } | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs_remove(&lfs, path) => 0; | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # outdated head test | ||||
| define.ITERATIONS = 20 | ||||
| define.COUNT = 10 | ||||
| define.LFS_BLOCK_CYCLES = [8, 1] | ||||
| define.LFS2_BLOCK_CYCLES = [8, 1] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // fill up filesystem so only ~16 blocks are left | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     memset(buffer, 0, 512); | ||||
|     while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { | ||||
|         lfs_file_write(&lfs, &file, buffer, 512) => 512; | ||||
|     while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, 512) => 512; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // make a child dir to use in bounded space | ||||
|     lfs_mkdir(&lfs, "child") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < ITERATIONS; j++) { | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_dir_open(&lfs, &dir, "child") => 0; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 0; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; | ||||
|             lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|  | ||||
|         lfs_dir_rewind(&lfs, &dir) => 0; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 2; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; | ||||
|             lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|  | ||||
|         lfs_dir_rewind(&lfs, &dir) => 0; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 2; | ||||
|         } | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|         lfs_dir_close(&lfs, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_remove(&lfs, path) => 0; | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for relocations, this is the same as the | ||||
| @@ -148,17 +148,17 @@ code = ''' | ||||
|          # almost every tree operation needs a relocation | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| if = '!(DEPTH == 3 && LFS2_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
| ] | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     srand(1); | ||||
| @@ -171,56 +171,56 @@ code = ''' | ||||
|         } | ||||
|  | ||||
|         // if it does not exist, we create it, else we destroy | ||||
|         int res = lfs_stat(&lfs, full_path, &info); | ||||
|         if (res == LFS_ERR_NOENT) { | ||||
|         int res = lfs2_stat(&lfs2, full_path, &info); | ||||
|         if (res == LFS2_ERR_NOENT) { | ||||
|             // create each directory in turn, ignore if dir already exists | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs_mkdir(&lfs, path); | ||||
|                 assert(!err || err == LFS_ERR_EXIST); | ||||
|                 err = lfs2_mkdir(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_EXIST); | ||||
|             } | ||||
|  | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 lfs_stat(&lfs, path, &info) => 0; | ||||
|                 lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                 assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                 assert(info.type == LFS_TYPE_DIR); | ||||
|                 assert(info.type == LFS2_TYPE_DIR); | ||||
|             } | ||||
|         } else { | ||||
|             // is valid dir? | ||||
|             assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); | ||||
|             assert(info.type == LFS_TYPE_DIR); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|             // try to delete path in reverse order, ignore if dir is not empty | ||||
|             for (int d = DEPTH-1; d >= 0; d--) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs_remove(&lfs, path); | ||||
|                 assert(!err || err == LFS_ERR_NOTEMPTY); | ||||
|                 err = lfs2_remove(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|             } | ||||
|  | ||||
|             lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; | ||||
|             lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|         } | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for relocations, but now with random renames! | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| if = '!(DEPTH == 3 && LFS2_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
| ] | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     srand(1); | ||||
| @@ -233,27 +233,27 @@ code = ''' | ||||
|         } | ||||
|  | ||||
|         // if it does not exist, we create it, else we destroy | ||||
|         int res = lfs_stat(&lfs, full_path, &info); | ||||
|         assert(!res || res == LFS_ERR_NOENT); | ||||
|         if (res == LFS_ERR_NOENT) { | ||||
|         int res = lfs2_stat(&lfs2, full_path, &info); | ||||
|         assert(!res || res == LFS2_ERR_NOENT); | ||||
|         if (res == LFS2_ERR_NOENT) { | ||||
|             // create each directory in turn, ignore if dir already exists | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs_mkdir(&lfs, path); | ||||
|                 assert(!err || err == LFS_ERR_EXIST); | ||||
|                 err = lfs2_mkdir(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_EXIST); | ||||
|             } | ||||
|  | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 lfs_stat(&lfs, path, &info) => 0; | ||||
|                 lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                 assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                 assert(info.type == LFS_TYPE_DIR); | ||||
|                 assert(info.type == LFS2_TYPE_DIR); | ||||
|             } | ||||
|         } else { | ||||
|             assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); | ||||
|             assert(info.type == LFS_TYPE_DIR); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|             // create new random path | ||||
|             char new_path[256]; | ||||
| @@ -262,17 +262,17 @@ code = ''' | ||||
|             } | ||||
|  | ||||
|             // if new path does not exist, rename, otherwise destroy | ||||
|             res = lfs_stat(&lfs, new_path, &info); | ||||
|             assert(!res || res == LFS_ERR_NOENT); | ||||
|             if (res == LFS_ERR_NOENT) { | ||||
|             res = lfs2_stat(&lfs2, new_path, &info); | ||||
|             assert(!res || res == LFS2_ERR_NOENT); | ||||
|             if (res == LFS2_ERR_NOENT) { | ||||
|                 // stop once some dir is renamed | ||||
|                 for (int d = 0; d < DEPTH; d++) { | ||||
|                     strcpy(&path[2*d], &full_path[2*d]); | ||||
|                     path[2*d+2] = '\0'; | ||||
|                     strcpy(&path[128+2*d], &new_path[2*d]); | ||||
|                     path[128+2*d+2] = '\0'; | ||||
|                     err = lfs_rename(&lfs, path, path+128); | ||||
|                     assert(!err || err == LFS_ERR_NOTEMPTY); | ||||
|                     err = lfs2_rename(&lfs2, path, path+128); | ||||
|                     assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|                     if (!err) { | ||||
|                         strcpy(path, path+128); | ||||
|                     } | ||||
| @@ -281,25 +281,25 @@ code = ''' | ||||
|                 for (int d = 0; d < DEPTH; d++) { | ||||
|                     strcpy(path, new_path); | ||||
|                     path[2*d+2] = '\0'; | ||||
|                     lfs_stat(&lfs, path, &info) => 0; | ||||
|                     lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                     assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                     assert(info.type == LFS_TYPE_DIR); | ||||
|                     assert(info.type == LFS2_TYPE_DIR); | ||||
|                 } | ||||
|                  | ||||
|                 lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; | ||||
|                 lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|             } else { | ||||
|                 // try to delete path in reverse order, | ||||
|                 // ignore if dir is not empty | ||||
|                 for (int d = DEPTH-1; d >= 0; d--) { | ||||
|                     strcpy(path, full_path); | ||||
|                     path[2*d+2] = '\0'; | ||||
|                     err = lfs_remove(&lfs, path); | ||||
|                     assert(!err || err == LFS_ERR_NOTEMPTY); | ||||
|                     err = lfs2_remove(&lfs2, path); | ||||
|                     assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|                 } | ||||
|  | ||||
|                 lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; | ||||
|                 lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -9,63 +9,63 @@ define = [ | ||||
|     {COUNT=4,   SKIP=2}, | ||||
| ] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size); | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     lfs_soff_t pos = -1; | ||||
|     lfs2_soff_t pos = -1; | ||||
|     size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < SKIP; i++) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs_file_tell(&lfs, &file); | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     assert(pos >= 0); | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_rewind(&lfs, &file) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, size, LFS2_SEEK_CUR) => 3*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_CUR) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs_file_size(&lfs, &file); | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # simple file seek and write | ||||
| @@ -78,109 +78,109 @@ define = [ | ||||
|     {COUNT=4,   SKIP=2}, | ||||
| ] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size); | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     lfs_soff_t pos = -1; | ||||
|     lfs2_soff_t pos = -1; | ||||
|     size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < SKIP; i++) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs_file_tell(&lfs, &file); | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     assert(pos >= 0); | ||||
|  | ||||
|     memcpy(buffer, "doggodogdog", size); | ||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; | ||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs_file_rewind(&lfs, &file) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs_file_size(&lfs, &file); | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # boundary seek and writes | ||||
| define.COUNT = 132 | ||||
| define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size); | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     size = strlen("hedgehoghog"); | ||||
|     const lfs_soff_t offsets[] = OFFSETS; | ||||
|     const lfs2_soff_t offsets[] = OFFSETS; | ||||
|  | ||||
|     for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { | ||||
|         lfs_soff_t off = offsets[i]; | ||||
|         lfs2_soff_t off = offsets[i]; | ||||
|         memcpy(buffer, "hedgehoghog", size); | ||||
|         lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|  | ||||
|         lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|         lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|  | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|         lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|         lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # out of bounds seek | ||||
| @@ -193,116 +193,116 @@ define = [ | ||||
|     {COUNT=4,   SKIP=3}, | ||||
| ] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size); | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     size = strlen("kittycatcat"); | ||||
|     lfs_file_size(&lfs, &file) => COUNT*size; | ||||
|     lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, | ||||
|             LFS_SEEK_SET) => (COUNT+SKIP)*size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => COUNT*size; | ||||
|     lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size, | ||||
|             LFS2_SEEK_SET) => (COUNT+SKIP)*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     memcpy(buffer, "porcupineee", size); | ||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, | ||||
|             LFS_SEEK_SET) => (COUNT+SKIP)*size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size, | ||||
|             LFS2_SEEK_SET) => (COUNT+SKIP)*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "porcupineee", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, COUNT*size, | ||||
|             LFS_SEEK_SET) => COUNT*size; | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_file_seek(&lfs2, &file, COUNT*size, | ||||
|             LFS2_SEEK_SET) => COUNT*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, -((COUNT+SKIP)*size), | ||||
|             LFS_SEEK_CUR) => LFS_ERR_INVAL; | ||||
|     lfs_file_tell(&lfs, &file) => (COUNT+1)*size; | ||||
|     lfs2_file_seek(&lfs2, &file, -((COUNT+SKIP)*size), | ||||
|             LFS2_SEEK_CUR) => LFS2_ERR_INVAL; | ||||
|     lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, -((COUNT+2*SKIP)*size), | ||||
|             LFS_SEEK_END) => LFS_ERR_INVAL; | ||||
|     lfs_file_tell(&lfs, &file) => (COUNT+1)*size; | ||||
|     lfs2_file_seek(&lfs2, &file, -((COUNT+2*SKIP)*size), | ||||
|             LFS2_SEEK_END) => LFS2_ERR_INVAL; | ||||
|     lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # inline write and seek | ||||
| define.SIZE = [2, 4, 128, 132] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "tinykitty", | ||||
|             LFS_O_RDWR | LFS_O_CREAT) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "tinykitty", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT) => 0; | ||||
|     int j = 0; | ||||
|     int k = 0; | ||||
|  | ||||
|     memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs_file_tell(&lfs, &file) => i+1; | ||||
|         lfs_file_size(&lfs, &file) => i+1; | ||||
|         lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => i+1; | ||||
|     } | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         uint8_t c; | ||||
|         lfs_file_read(&lfs, &file, &c, 1) => 1; | ||||
|         lfs2_file_read(&lfs2, &file, &c, 1) => 1; | ||||
|         c => buffer[k++ % 26]; | ||||
|     } | ||||
|  | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => SIZE; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => SIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs_file_tell(&lfs, &file) => i+1; | ||||
|         lfs_file_size(&lfs, &file) => SIZE; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|         lfs_file_tell(&lfs, &file) => i+1; | ||||
|         lfs_file_size(&lfs, &file) => SIZE; | ||||
|         lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|         if (i < SIZE-2) { | ||||
|             uint8_t c[3]; | ||||
|             lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i; | ||||
|             lfs_file_read(&lfs, &file, &c, 3) => 3; | ||||
|             lfs_file_tell(&lfs, &file) => i+3; | ||||
|             lfs_file_size(&lfs, &file) => SIZE; | ||||
|             lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1; | ||||
|             lfs_file_tell(&lfs, &file) => i+1; | ||||
|             lfs_file_size(&lfs, &file) => SIZE; | ||||
|             lfs2_file_seek(&lfs2, &file, -1, LFS2_SEEK_CUR) => i; | ||||
|             lfs2_file_read(&lfs2, &file, &c, 3) => 3; | ||||
|             lfs2_file_tell(&lfs2, &file) => i+3; | ||||
|             lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|             lfs2_file_seek(&lfs2, &file, i+1, LFS2_SEEK_SET) => i+1; | ||||
|             lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|             lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         uint8_t c; | ||||
|         lfs_file_read(&lfs, &file, &c, 1) => 1; | ||||
|         lfs2_file_read(&lfs2, &file, &c, 1) => 1; | ||||
|         c => buffer[k++ % 26]; | ||||
|     } | ||||
|  | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => SIZE; | ||||
|     lfs_file_size(&lfs, &file) => SIZE; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => SIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # file seek and write with power-loss | ||||
| @@ -310,71 +310,71 @@ code = ''' | ||||
| define.COUNT = [4, 64, 128] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); | ||||
|     assert(!err || err == LFS_ERR_NOENT); | ||||
|     err = lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY); | ||||
|     assert(!err || err == LFS2_ERR_NOENT); | ||||
|     if (!err) { | ||||
|         if (lfs_file_size(&lfs, &file) != 0) { | ||||
|             lfs_file_size(&lfs, &file) => 11*COUNT; | ||||
|         if (lfs2_file_size(&lfs2, &file) != 0) { | ||||
|             lfs2_file_size(&lfs2, &file) => 11*COUNT; | ||||
|             for (int j = 0; j < COUNT; j++) { | ||||
|                 memset(buffer, 0, 11+1); | ||||
|                 lfs_file_read(&lfs, &file, buffer, 11) => 11; | ||||
|                 lfs2_file_read(&lfs2, &file, buffer, 11) => 11; | ||||
|                 assert(memcmp(buffer, "kittycatcat", 11) == 0 || | ||||
|                        memcmp(buffer, "doggodogdog", 11) == 0); | ||||
|             } | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     if (lfs_file_size(&lfs, &file) == 0) { | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     if (lfs2_file_size(&lfs2, &file) == 0) { | ||||
|         for (int j = 0; j < COUNT; j++) { | ||||
|             strcpy((char*)buffer, "kittycatcat"); | ||||
|             size = strlen((char*)buffer); | ||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "doggodogdog"); | ||||
|     size = strlen((char*)buffer); | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => COUNT*size; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => COUNT*size; | ||||
|     // seek and write using quadratic probing to touch all | ||||
|     // 11-byte words in the file | ||||
|     lfs_off_t off = 0; | ||||
|     lfs2_off_t off = 0; | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         off = (5*off + 1) % COUNT; | ||||
|         lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         assert(memcmp(buffer, "kittycatcat", size) == 0 || | ||||
|                memcmp(buffer, "doggodogdog", size) == 0); | ||||
|         if (memcmp(buffer, "doggodogdog", size) != 0) { | ||||
|             lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; | ||||
|             lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|             strcpy((char*)buffer, "doggodogdog"); | ||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|             lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|             lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, "doggodogdog", size) == 0); | ||||
|             lfs_file_sync(&lfs, &file) => 0; | ||||
|             lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_sync(&lfs2, &file) => 0; | ||||
|             lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, "doggodogdog", size) == 0); | ||||
|         } | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => COUNT*size; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => COUNT*size; | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         assert(memcmp(buffer, "doggodogdog", size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -1,127 +1,127 @@ | ||||
| [[case]] # simple formatting test | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # mount/unmount | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant format | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid mount | ||||
| code = ''' | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # expanding superblock | ||||
| define.LFS_BLOCK_CYCLES = [32, 33, 1] | ||||
| define.LFS2_BLOCK_CYCLES = [32, 33, 1] | ||||
| define.N = [10, 100, 1000] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         lfs_file_open(&lfs, &file, "dummy", | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs_stat(&lfs, "dummy", &info) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, "dummy", | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|         assert(strcmp(info.name, "dummy") == 0); | ||||
|         assert(info.type == LFS_TYPE_REG); | ||||
|         lfs_remove(&lfs, "dummy") => 0; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         lfs2_remove(&lfs2, "dummy") => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // one last check after power-cycle | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "dummy", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_stat(&lfs, "dummy", &info) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "dummy", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|     assert(strcmp(info.name, "dummy") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # expanding superblock with power cycle | ||||
| define.LFS_BLOCK_CYCLES = [32, 33, 1] | ||||
| define.LFS2_BLOCK_CYCLES = [32, 33, 1] | ||||
| define.N = [10, 100, 1000] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         // remove lingering dummy? | ||||
|         err = lfs_stat(&lfs, "dummy", &info); | ||||
|         assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); | ||||
|         err = lfs2_stat(&lfs2, "dummy", &info); | ||||
|         assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0)); | ||||
|         if (!err) { | ||||
|             assert(strcmp(info.name, "dummy") == 0); | ||||
|             assert(info.type == LFS_TYPE_REG); | ||||
|             lfs_remove(&lfs, "dummy") => 0; | ||||
|             assert(info.type == LFS2_TYPE_REG); | ||||
|             lfs2_remove(&lfs2, "dummy") => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_file_open(&lfs, &file, "dummy", | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs_stat(&lfs, "dummy", &info) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, "dummy", | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|         assert(strcmp(info.name, "dummy") == 0); | ||||
|         assert(info.type == LFS_TYPE_REG); | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
|  | ||||
|     // one last check after power-cycle | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "dummy", &info) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|     assert(strcmp(info.name, "dummy") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant expanding superblock | ||||
| define.LFS_BLOCK_CYCLES = [2, 1] | ||||
| define.LFS2_BLOCK_CYCLES = [2, 1] | ||||
| define.N = 24 | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         // remove lingering dummy? | ||||
|         err = lfs_stat(&lfs, "dummy", &info); | ||||
|         assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); | ||||
|         err = lfs2_stat(&lfs2, "dummy", &info); | ||||
|         assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0)); | ||||
|         if (!err) { | ||||
|             assert(strcmp(info.name, "dummy") == 0); | ||||
|             assert(info.type == LFS_TYPE_REG); | ||||
|             lfs_remove(&lfs, "dummy") => 0; | ||||
|             assert(info.type == LFS2_TYPE_REG); | ||||
|             lfs2_remove(&lfs2, "dummy") => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_file_open(&lfs, &file, "dummy", | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs_stat(&lfs, "dummy", &info) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, "dummy", | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|         assert(strcmp(info.name, "dummy") == 0); | ||||
|         assert(info.type == LFS_TYPE_REG); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|     } | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // one last check after power-cycle | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "dummy", &info) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|     assert(strcmp(info.name, "dummy") == 0); | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -2,198 +2,198 @@ | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldynoop", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|      | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("hair"); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncate and read | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldyread", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("hair"); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("hair"); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # write, truncate, and read | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "sequence", | ||||
|             LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "sequence", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|     size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); | ||||
|     lfs_size_t qsize = size / 4; | ||||
|     size = lfs2_min(lfs2.cfg->cache_size, sizeof(buffer)/2); | ||||
|     lfs2_size_t qsize = size / 4; | ||||
|     uint8_t *wb = buffer; | ||||
|     uint8_t *rb = buffer + size; | ||||
|     for (lfs_off_t j = 0; j < size; ++j) { | ||||
|     for (lfs2_off_t j = 0; j < size; ++j) { | ||||
|         wb[j] = j; | ||||
|     } | ||||
|  | ||||
|     /* Spread sequence over size */ | ||||
|     lfs_file_write(&lfs, &file, wb, size) => size; | ||||
|     lfs_file_size(&lfs, &file) => size; | ||||
|     lfs_file_tell(&lfs, &file) => size; | ||||
|     lfs2_file_write(&lfs2, &file, wb, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_tell(&lfs2, &file) => size; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => 0; | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|  | ||||
|     /* Chop off the last quarter */ | ||||
|     lfs_size_t trunc = size - qsize; | ||||
|     lfs_file_truncate(&lfs, &file, trunc) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => 0; | ||||
|     lfs_file_size(&lfs, &file) => trunc; | ||||
|     lfs2_size_t trunc = size - qsize; | ||||
|     lfs2_file_truncate(&lfs2, &file, trunc) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|  | ||||
|     /* Read should produce first 3/4 */ | ||||
|     lfs_file_read(&lfs, &file, rb, size) => trunc; | ||||
|     lfs2_file_read(&lfs2, &file, rb, size) => trunc; | ||||
|     memcmp(rb, wb, trunc) => 0; | ||||
|  | ||||
|     /* Move to 1/4 */ | ||||
|     lfs_file_size(&lfs, &file) => trunc; | ||||
|     lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize; | ||||
|     lfs_file_tell(&lfs, &file) => qsize; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|     lfs2_file_seek(&lfs2, &file, qsize, LFS2_SEEK_SET) => qsize; | ||||
|     lfs2_file_tell(&lfs2, &file) => qsize; | ||||
|  | ||||
|     /* Chop to 1/2 */ | ||||
|     trunc -= qsize; | ||||
|     lfs_file_truncate(&lfs, &file, trunc) => 0; | ||||
|     lfs_file_tell(&lfs, &file) => qsize; | ||||
|     lfs_file_size(&lfs, &file) => trunc; | ||||
|     lfs2_file_truncate(&lfs2, &file, trunc) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => qsize; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|      | ||||
|     /* Read should produce second quarter */ | ||||
|     lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; | ||||
|     lfs2_file_read(&lfs2, &file, rb, size) => trunc - qsize; | ||||
|     memcmp(rb, wb + qsize, trunc - qsize) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncate and write | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldywrite", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     strcpy((char*)buffer, "bald"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("bald"); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "bald", size) => 0; | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncate write under powerloss | ||||
| @@ -202,64 +202,64 @@ define.MEDIUMSIZE = [32, 1024] | ||||
| define.LARGESIZE = 2048 | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs_mount(&lfs, &cfg); | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs_format(&lfs, &cfg) => 0; | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); | ||||
|     assert(!err || err == LFS_ERR_NOENT); | ||||
|     err = lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDONLY); | ||||
|     assert(!err || err == LFS2_ERR_NOENT); | ||||
|     if (!err) { | ||||
|         size = lfs_file_size(&lfs, &file); | ||||
|         size = lfs2_file_size(&lfs2, &file); | ||||
|         assert(size == 0 || | ||||
|                 size == LARGESIZE || | ||||
|                 size == MEDIUMSIZE || | ||||
|                 size == SMALLSIZE); | ||||
|         for (lfs_off_t j = 0; j < size; j += 4) { | ||||
|             lfs_file_read(&lfs, &file, buffer, 4) => 4; | ||||
|         for (lfs2_off_t j = 0; j < size; j += 4) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, 4) => 4; | ||||
|             assert(memcmp(buffer, "hair", 4) == 0 || | ||||
|                    memcmp(buffer, "bald", 4) == 0 || | ||||
|                    memcmp(buffer, "comb", 4) == 0); | ||||
|         } | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "baldy", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|     lfs_file_size(&lfs, &file) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldy", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => 0; | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => LARGESIZE; | ||||
|     lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     strcpy((char*)buffer, "bald"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs_file_truncate(&lfs, &file, SMALLSIZE) => 0; | ||||
|     lfs_file_size(&lfs, &file) => SMALLSIZE; | ||||
|     lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, SMALLSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SMALLSIZE; | ||||
|     strcpy((char*)buffer, "comb"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < SMALLSIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < SMALLSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => SMALLSIZE; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SMALLSIZE; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # more aggressive general truncation tests | ||||
| @@ -270,10 +270,10 @@ define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     #define COUNT 5 | ||||
|     const struct { | ||||
|         lfs_off_t startsizes[COUNT]; | ||||
|         lfs_off_t startseeks[COUNT]; | ||||
|         lfs_off_t hotsizes[COUNT]; | ||||
|         lfs_off_t coldsizes[COUNT]; | ||||
|         lfs2_off_t startsizes[COUNT]; | ||||
|         lfs2_off_t startseeks[COUNT]; | ||||
|         lfs2_off_t hotsizes[COUNT]; | ||||
|         lfs2_off_t coldsizes[COUNT]; | ||||
|     } configs[] = { | ||||
|         // cold shrinking | ||||
|         {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
| @@ -307,133 +307,133 @@ code = ''' | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, | ||||
|     }; | ||||
|  | ||||
|     const lfs_off_t *startsizes = configs[CONFIG].startsizes; | ||||
|     const lfs_off_t *startseeks = configs[CONFIG].startseeks; | ||||
|     const lfs_off_t *hotsizes   = configs[CONFIG].hotsizes; | ||||
|     const lfs_off_t *coldsizes  = configs[CONFIG].coldsizes; | ||||
|     const lfs2_off_t *startsizes = configs[CONFIG].startsizes; | ||||
|     const lfs2_off_t *startseeks = configs[CONFIG].startseeks; | ||||
|     const lfs2_off_t *hotsizes   = configs[CONFIG].hotsizes; | ||||
|     const lfs2_off_t *coldsizes  = configs[CONFIG].coldsizes; | ||||
|  | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs_file_open(&lfs, &file, path, | ||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|         strcpy((char*)buffer, "hair"); | ||||
|         size = strlen((char*)buffer); | ||||
|         for (lfs_off_t j = 0; j < startsizes[i]; j += size) { | ||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         for (lfs2_off_t j = 0; j < startsizes[i]; j += size) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|         lfs_file_size(&lfs, &file) => startsizes[i]; | ||||
|         lfs2_file_size(&lfs2, &file) => startsizes[i]; | ||||
|  | ||||
|         if (startseeks[i] != startsizes[i]) { | ||||
|             lfs_file_seek(&lfs, &file, | ||||
|                     startseeks[i], LFS_SEEK_SET) => startseeks[i]; | ||||
|             lfs2_file_seek(&lfs2, &file, | ||||
|                     startseeks[i], LFS2_SEEK_SET) => startseeks[i]; | ||||
|         } | ||||
|  | ||||
|         lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0; | ||||
|         lfs_file_size(&lfs, &file) => hotsizes[i]; | ||||
|         lfs2_file_truncate(&lfs2, &file, hotsizes[i]) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => hotsizes[i]; | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; | ||||
|         lfs_file_size(&lfs, &file) => hotsizes[i]; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDWR) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => hotsizes[i]; | ||||
|  | ||||
|         size = strlen("hair"); | ||||
|         lfs_off_t j = 0; | ||||
|         lfs2_off_t j = 0; | ||||
|         for (; j < startsizes[i] && j < hotsizes[i]; j += size) { | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "hair", size) => 0; | ||||
|         } | ||||
|  | ||||
|         for (; j < hotsizes[i]; j += size) { | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0; | ||||
|         lfs_file_size(&lfs, &file) => coldsizes[i]; | ||||
|         lfs2_file_truncate(&lfs2, &file, coldsizes[i]) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => coldsizes[i]; | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|         lfs_file_size(&lfs, &file) => coldsizes[i]; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => coldsizes[i]; | ||||
|  | ||||
|         size = strlen("hair"); | ||||
|         lfs_off_t j = 0; | ||||
|         lfs2_off_t j = 0; | ||||
|         for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; | ||||
|                 j += size) { | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "hair", size) => 0; | ||||
|         } | ||||
|  | ||||
|         for (; j < coldsizes[i]; j += size) { | ||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs_file_close(&lfs, &file) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # noop truncate | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldynoop", | ||||
|             LFS_O_RDWR | LFS_O_CREAT) => 0; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|         // this truncate should do nothing | ||||
|         lfs_file_truncate(&lfs, &file, j+size) => 0; | ||||
|         lfs2_file_truncate(&lfs2, &file, j+size) => 0; | ||||
|     } | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     // should do nothing again | ||||
|     lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // still there after reboot? | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; | ||||
|     lfs_file_size(&lfs, &file) => MEDIUMSIZE; | ||||
|     for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user