diff --git a/.gitignore b/.gitignore index 36f92cd..8869407 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ # Testing things blocks/ -lfs +lfs1 test.c diff --git a/.travis.yml b/.travis.yml index f8306b1..fb0697b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,16 +18,16 @@ script: - make test QUIET=1 # run tests with a few different configurations - - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1" - - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512" - - make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048" + - make test QUIET=1 CFLAGS+="-DLFS1_READ_SIZE=1 -DLFS1_PROG_SIZE=1" + - make test QUIET=1 CFLAGS+="-DLFS1_READ_SIZE=512 -DLFS1_PROG_SIZE=512" + - make test QUIET=1 CFLAGS+="-DLFS1_BLOCK_COUNT=1023 -DLFS1_LOOKAHEAD=2048" - - make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS" + - make clean test QUIET=1 CFLAGS+="-DLFS1_NO_INTRINSICS" # compile and find the code size with the smallest configuration - make clean size - OBJ="$(ls lfs*.o | tr '\n' ' ')" - CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR" + OBJ="$(ls lfs1*.o | tr '\n' ' ')" + CFLAGS+="-DLFS1_NO_ASSERT -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR" | tee sizes # update status if we succeeded, compare with master if possible @@ -119,8 +119,8 @@ jobs: # self-host test - make -C littlefs-fuse - - littlefs-fuse/lfs --format /dev/loop0 - - littlefs-fuse/lfs /dev/loop0 mount + - littlefs-fuse/lfs1 --format /dev/loop0 + - littlefs-fuse/lfs1 /dev/loop0 mount - ls mount - mkdir mount/littlefs @@ -138,55 +138,55 @@ jobs: - | bash << 'SCRIPT' set -ev - # Find version defined in lfs.h - LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3) - LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16))) - LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0))) + # Find version defined in lfs1.h + LFS1_VERSION=$(grep -ox '#define LFS1_VERSION .*' lfs1.h | cut -d ' ' -f3) + LFS1_VERSION_MAJOR=$((0xffff & ($LFS1_VERSION >> 16))) + LFS1_VERSION_MINOR=$((0xffff & ($LFS1_VERSION >> 0))) # Grab latests patch from repo tags, default to 0, needs finagling # to get past github's pagination api - PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR. + PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS1_VERSION_MAJOR.$LFS1_VERSION_MINOR. PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I \ | sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' \ || echo $PREV_URL) - LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \ + LFS1_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \ | jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g") .captures[].string | tonumber) | max + 1' \ || echo 0) # We have our new version - LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH" - echo "VERSION $LFS_VERSION" + LFS1_VERSION="v$LFS1_VERSION_MAJOR.$LFS1_VERSION_MINOR.$LFS1_VERSION_PATCH" + echo "VERSION $LFS1_VERSION" # Check that we're the most recent commit CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \ | jq -re '.sha') [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0 # Create major branch - git branch v$LFS_VERSION_MAJOR HEAD + git branch v$LFS1_VERSION_MAJOR HEAD # Create major prefix branch git config user.name "geky bot" git config user.email "bot@geky.net" git fetch https://github.com/$TRAVIS_REPO_SLUG.git \ - --depth=50 v$LFS_VERSION_MAJOR-prefix || true - ./scripts/prefix.py lfs$LFS_VERSION_MAJOR - git branch v$LFS_VERSION_MAJOR-prefix $( \ + --depth=50 v$LFS1_VERSION_MAJOR-prefix || true + ./scripts/prefix.py lfs1$LFS1_VERSION_MAJOR + git branch v$LFS1_VERSION_MAJOR-prefix $( \ git commit-tree $(git write-tree) \ $(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \ -p HEAD \ - -m "Generated v$LFS_VERSION_MAJOR prefixes") + -m "Generated v$LFS1_VERSION_MAJOR prefixes") git reset --hard # Update major version branches (vN and vN-prefix) git push https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \ - v$LFS_VERSION_MAJOR \ - v$LFS_VERSION_MAJOR-prefix + v$LFS1_VERSION_MAJOR \ + v$LFS1_VERSION_MAJOR-prefix # Create patch version tag (vN.N.N) curl -f -u "$GEKY_BOT_RELEASES" -X POST \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs \ -d "{ - \"ref\": \"refs/tags/$LFS_VERSION\", + \"ref\": \"refs/tags/$LFS1_VERSION\", \"sha\": \"$TRAVIS_COMMIT\" }" # Create minor release? - [[ "$LFS_VERSION" == *.0 ]] || exit 0 + [[ "$LFS1_VERSION" == *.0 ]] || exit 0 # Build release notes PREV=$(git tag --sort=-v:refname -l "v*.0" | head -1) if [ ! -z "$PREV" ] @@ -200,8 +200,8 @@ jobs: curl -f -u "$GEKY_BOT_RELEASES" -X POST \ https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \ -d "{ - \"tag_name\": \"$LFS_VERSION\", - \"name\": \"${LFS_VERSION%.0}\", + \"tag_name\": \"$LFS1_VERSION\", + \"name\": \"${LFS1_VERSION%.0}\", \"draft\": true, \"body\": $(jq -sR '.' <<< "$CHANGES") }" #" diff --git a/Makefile b/Makefile index 17d3616..6d29cb4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -TARGET = lfs.a +TARGET = lfs1.a ifneq ($(wildcard test.c main.c),) -override TARGET = lfs +override TARGET = lfs1 endif CC ?= gcc @@ -50,7 +50,7 @@ endif -include $(DEP) -lfs: $(OBJ) +lfs1: $(OBJ) $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ %.a: $(OBJ) diff --git a/README.md b/README.md index a47f6e2..3713993 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ main runs. The program can be interrupted at any time without losing track of how many times it has been booted and without corrupting the filesystem: ``` c -#include "lfs.h" +#include "lfs1.h" // variables used by the filesystem -lfs_t lfs; -lfs_file_t file; +lfs1_t lfs1; +lfs1_file_t file; // configuration of the filesystem is provided by this struct -const struct lfs_config cfg = { +const struct lfs1_config cfg = { // block device operations .read = user_provided_block_device_read, .prog = user_provided_block_device_prog, @@ -55,30 +55,30 @@ const struct lfs_config cfg = { // entry point int main(void) { // mount the filesystem - int err = lfs_mount(&lfs, &cfg); + int err = lfs1_mount(&lfs1, &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); + lfs1_format(&lfs1, &cfg); + lfs1_mount(&lfs1, &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)); + lfs1_file_open(&lfs1, &file, "boot_count", LFS1_O_RDWR | LFS1_O_CREAT); + lfs1_file_read(&lfs1, &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)); + lfs1_file_rewind(&lfs1, &file); + lfs1_file_write(&lfs1, &file, &boot_count, sizeof(boot_count)); // remember the storage is not updated until the file is closed successfully - lfs_file_close(&lfs, &file); + lfs1_file_close(&lfs1, &file); // release any resources we were using - lfs_unmount(&lfs); + lfs1_unmount(&lfs1); // print the boot count printf("boot_count: %d\n", boot_count); @@ -88,7 +88,7 @@ int main(void) { ## Usage Detailed documentation (or at least as much detail as is currently available) -can be found in the comments in [lfs.h](lfs.h). +can be found in the comments in [lfs1.h](lfs1.h). As you may have noticed, littlefs takes in a configuration structure that defines how the filesystem operates. The configuration struct provides the @@ -96,9 +96,9 @@ filesystem with the block device operations and dimensions, tweakable parameters that tradeoff memory usage for performance, and optional static buffers if the user wants to avoid dynamic memory. -The state of the littlefs is stored in the `lfs_t` type which is left up +The state of the littlefs is stored in the `lfs1_t` type which is left up to the user to allocate, allowing multiple filesystems to be in use -simultaneously. With the `lfs_t` and configuration struct, a user can +simultaneously. With the `lfs1_t` and configuration struct, a user can format a block device or mount the filesystem. Once mounted, the littlefs provides a full set of POSIX-like file and @@ -112,11 +112,11 @@ filesystem until sync or close is called on the file. ## Other notes 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 lfs1_error` in +[lfs1.h](lfs1.h), or an error returned by the user's block device operations. In the configuration struct, the `prog` and `erase` function provided by the -user may return a `LFS_ERR_CORRUPT` error if the implementation already can +user may return a `LFS1_ERR_CORRUPT` error if the implementation already can detect corrupt blocks. However, the wear leveling does not depend on the return code of these functions, instead all data is read back and checked for integrity. @@ -139,7 +139,7 @@ with all the nitty-gritty details. Can be useful for developing tooling. ## Testing The littlefs comes with a test suite designed to run on a PC using the -[emulated block device](emubd/lfs_emubd.h) found in the emubd directory. +[emulated block device](emubd/lfs1_emubd.h) found in the emubd directory. The tests assume a Linux environment and can be started with make: ``` bash diff --git a/emubd/lfs_emubd.c b/emubd/lfs1_emubd.c similarity index 77% rename from emubd/lfs_emubd.c rename to emubd/lfs1_emubd.c index e44602c..ef57c04 100644 --- a/emubd/lfs_emubd.c +++ b/emubd/lfs1_emubd.c @@ -4,7 +4,7 @@ * Copyright (c) 2017, Arm Limited. All rights reserved. * SPDX-License-Identifier: BSD-3-Clause */ -#include "emubd/lfs_emubd.h" +#include "emubd/lfs1_emubd.h" #include #include @@ -20,8 +20,8 @@ // Block device emulated on existing filesystem -int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { - lfs_emubd_t *emu = cfg->context; +int lfs1_emubd_create(const struct lfs1_config *cfg, const char *path) { + lfs1_emubd_t *emu = cfg->context; emu->cfg.read_size = cfg->read_size; emu->cfg.prog_size = cfg->prog_size; emu->cfg.block_size = cfg->block_size; @@ -29,7 +29,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { // Allocate buffer for creating children files size_t pathlen = strlen(path); - emu->path = malloc(pathlen + 1 + LFS_NAME_MAX + 1); + emu->path = malloc(pathlen + 1 + LFS1_NAME_MAX + 1); if (!emu->path) { return -ENOMEM; } @@ -37,7 +37,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { strcpy(emu->path, path); emu->path[pathlen] = '/'; emu->child = &emu->path[pathlen+1]; - memset(emu->child, '\0', LFS_NAME_MAX+1); + memset(emu->child, '\0', LFS1_NAME_MAX+1); // Create directory if it doesn't exist int err = mkdir(path, 0777); @@ -46,7 +46,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { } // Load stats to continue incrementing - snprintf(emu->child, LFS_NAME_MAX, "stats"); + snprintf(emu->child, LFS1_NAME_MAX, "stats"); FILE *f = fopen(emu->path, "r"); if (!f && errno != ENOENT) { @@ -70,16 +70,16 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { return 0; } -void lfs_emubd_destroy(const struct lfs_config *cfg) { - lfs_emubd_sync(cfg); +void lfs1_emubd_destroy(const struct lfs1_config *cfg) { + lfs1_emubd_sync(cfg); - lfs_emubd_t *emu = cfg->context; + lfs1_emubd_t *emu = cfg->context; free(emu->path); } -int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) { - lfs_emubd_t *emu = cfg->context; +int lfs1_emubd_read(const struct lfs1_config *cfg, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size) { + lfs1_emubd_t *emu = cfg->context; uint8_t *data = buffer; // Check if read is valid @@ -91,7 +91,7 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, memset(data, 0, size); // Read data - snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); + snprintf(emu->child, LFS1_NAME_MAX, "%" PRIx32, block); FILE *f = fopen(emu->path, "rb"); if (!f && errno != ENOENT) { @@ -119,9 +119,9 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, return 0; } -int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - lfs_emubd_t *emu = cfg->context; +int lfs1_emubd_prog(const struct lfs1_config *cfg, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + lfs1_emubd_t *emu = cfg->context; const uint8_t *data = buffer; // Check if write is valid @@ -130,7 +130,7 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, assert(block < cfg->block_count); // Program data - snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); + snprintf(emu->child, LFS1_NAME_MAX, "%" PRIx32, block); FILE *f = fopen(emu->path, "r+b"); if (!f) { @@ -170,14 +170,14 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, return 0; } -int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { - lfs_emubd_t *emu = cfg->context; +int lfs1_emubd_erase(const struct lfs1_config *cfg, lfs1_block_t block) { + lfs1_emubd_t *emu = cfg->context; // Check if erase is valid assert(block < cfg->block_count); // Erase the block - snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); + snprintf(emu->child, LFS1_NAME_MAX, "%" PRIx32, block); struct stat st; int err = stat(emu->path, &st); if (err && errno != ENOENT) { @@ -207,11 +207,11 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { return 0; } -int lfs_emubd_sync(const struct lfs_config *cfg) { - lfs_emubd_t *emu = cfg->context; +int lfs1_emubd_sync(const struct lfs1_config *cfg) { + lfs1_emubd_t *emu = cfg->context; // Just write out info/stats for later lookup - snprintf(emu->child, LFS_NAME_MAX, "config"); + snprintf(emu->child, LFS1_NAME_MAX, "config"); FILE *f = fopen(emu->path, "w"); if (!f) { return -errno; @@ -227,7 +227,7 @@ int lfs_emubd_sync(const struct lfs_config *cfg) { return -errno; } - snprintf(emu->child, LFS_NAME_MAX, "stats"); + snprintf(emu->child, LFS1_NAME_MAX, "stats"); f = fopen(emu->path, "w"); if (!f) { return -errno; diff --git a/emubd/lfs_emubd.h b/emubd/lfs1_emubd.h similarity index 51% rename from emubd/lfs_emubd.h rename to emubd/lfs1_emubd.h index 0fd4387..c27f2ba 100644 --- a/emubd/lfs_emubd.h +++ b/emubd/lfs1_emubd.h @@ -4,11 +4,11 @@ * Copyright (c) 2017, Arm Limited. All rights reserved. * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef LFS_EMUBD_H -#define LFS_EMUBD_H +#ifndef LFS1_EMUBD_H +#define LFS1_EMUBD_H -#include "lfs.h" -#include "lfs_util.h" +#include "lfs1.h" +#include "lfs1_util.h" #ifdef __cplusplus extern "C" @@ -17,25 +17,25 @@ extern "C" // Config options -#ifndef LFS_EMUBD_READ_SIZE -#define LFS_EMUBD_READ_SIZE 1 +#ifndef LFS1_EMUBD_READ_SIZE +#define LFS1_EMUBD_READ_SIZE 1 #endif -#ifndef LFS_EMUBD_PROG_SIZE -#define LFS_EMUBD_PROG_SIZE 1 +#ifndef LFS1_EMUBD_PROG_SIZE +#define LFS1_EMUBD_PROG_SIZE 1 #endif -#ifndef LFS_EMUBD_ERASE_SIZE -#define LFS_EMUBD_ERASE_SIZE 512 +#ifndef LFS1_EMUBD_ERASE_SIZE +#define LFS1_EMUBD_ERASE_SIZE 512 #endif -#ifndef LFS_EMUBD_TOTAL_SIZE -#define LFS_EMUBD_TOTAL_SIZE 524288 +#ifndef LFS1_EMUBD_TOTAL_SIZE +#define LFS1_EMUBD_TOTAL_SIZE 524288 #endif // The emu bd state -typedef struct lfs_emubd { +typedef struct lfs1_emubd { char *path; char *child; @@ -51,33 +51,33 @@ typedef struct lfs_emubd { uint32_t block_size; uint32_t block_count; } cfg; -} lfs_emubd_t; +} lfs1_emubd_t; // Create a block device using path for the directory to store blocks -int lfs_emubd_create(const struct lfs_config *cfg, const char *path); +int lfs1_emubd_create(const struct lfs1_config *cfg, const char *path); // Clean up memory associated with emu block device -void lfs_emubd_destroy(const struct lfs_config *cfg); +void lfs1_emubd_destroy(const struct lfs1_config *cfg); // Read a block -int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size); +int lfs1_emubd_read(const struct lfs1_config *cfg, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size); // Program a block // // The block must have previously been erased. -int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size); +int lfs1_emubd_prog(const struct lfs1_config *cfg, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size); // Erase a block // // A block must be erased before being programmed. The // state of an erased block is undefined. -int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block); +int lfs1_emubd_erase(const struct lfs1_config *cfg, lfs1_block_t block); // Sync the block device -int lfs_emubd_sync(const struct lfs_config *cfg); +int lfs1_emubd_sync(const struct lfs1_config *cfg); #ifdef __cplusplus diff --git a/lfs.c b/lfs.c deleted file mode 100644 index ed7f687..0000000 --- a/lfs.c +++ /dev/null @@ -1,2583 +0,0 @@ -/* - * The little filesystem - * - * Copyright (c) 2017, Arm Limited. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause - */ -#include "lfs.h" -#include "lfs_util.h" - -#include - - -/// Caching block device operations /// -static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, - const lfs_cache_t *pcache, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) { - uint8_t *data = buffer; - LFS_ASSERT(block < lfs->cfg->block_count); - - while (size > 0) { - if (pcache && block == pcache->block && off >= pcache->off && - off < pcache->off + lfs->cfg->prog_size) { - // is already in pcache? - lfs_size_t diff = lfs_min(size, - lfs->cfg->prog_size - (off-pcache->off)); - memcpy(data, &pcache->buffer[off-pcache->off], diff); - - data += diff; - off += diff; - size -= diff; - continue; - } - - if (block == rcache->block && off >= rcache->off && - off < rcache->off + lfs->cfg->read_size) { - // is already in rcache? - lfs_size_t diff = lfs_min(size, - lfs->cfg->read_size - (off-rcache->off)); - memcpy(data, &rcache->buffer[off-rcache->off], diff); - - data += diff; - off += diff; - size -= diff; - continue; - } - - if (off % lfs->cfg->read_size == 0 && size >= lfs->cfg->read_size) { - // bypass cache? - lfs_size_t diff = size - (size % lfs->cfg->read_size); - int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); - if (err) { - return err; - } - - data += diff; - off += diff; - size -= diff; - continue; - } - - // load to cache, first condition can no longer fail - rcache->block = block; - rcache->off = off - (off % lfs->cfg->read_size); - int err = lfs->cfg->read(lfs->cfg, rcache->block, - rcache->off, rcache->buffer, lfs->cfg->read_size); - if (err) { - return err; - } - } - - return 0; -} - -static int lfs_cache_cmp(lfs_t *lfs, lfs_cache_t *rcache, - const lfs_cache_t *pcache, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - const uint8_t *data = buffer; - - for (lfs_off_t i = 0; i < size; i++) { - uint8_t c; - int err = lfs_cache_read(lfs, rcache, pcache, - block, off+i, &c, 1); - if (err) { - return err; - } - - if (c != data[i]) { - return false; - } - } - - return true; -} - -static int lfs_cache_crc(lfs_t *lfs, lfs_cache_t *rcache, - const lfs_cache_t *pcache, lfs_block_t block, - lfs_off_t off, lfs_size_t size, uint32_t *crc) { - for (lfs_off_t i = 0; i < size; i++) { - uint8_t c; - int err = lfs_cache_read(lfs, rcache, pcache, - block, off+i, &c, 1); - if (err) { - return err; - } - - lfs_crc(crc, &c, 1); - } - - return 0; -} - -static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { - // do not zero, cheaper if cache is readonly or only going to be - // written with identical data (during relocates) - (void)lfs; - rcache->block = 0xffffffff; -} - -static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { - // zero to avoid information leak - memset(pcache->buffer, 0xff, lfs->cfg->prog_size); - pcache->block = 0xffffffff; -} - -static int lfs_cache_flush(lfs_t *lfs, - lfs_cache_t *pcache, lfs_cache_t *rcache) { - if (pcache->block != 0xffffffff) { - int err = lfs->cfg->prog(lfs->cfg, pcache->block, - pcache->off, pcache->buffer, lfs->cfg->prog_size); - if (err) { - return err; - } - - if (rcache) { - int res = lfs_cache_cmp(lfs, rcache, NULL, pcache->block, - pcache->off, pcache->buffer, lfs->cfg->prog_size); - if (res < 0) { - return res; - } - - if (!res) { - return LFS_ERR_CORRUPT; - } - } - - lfs_cache_zero(lfs, pcache); - } - - return 0; -} - -static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *pcache, - lfs_cache_t *rcache, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - const uint8_t *data = buffer; - LFS_ASSERT(block < lfs->cfg->block_count); - - while (size > 0) { - if (block == pcache->block && off >= pcache->off && - off < pcache->off + lfs->cfg->prog_size) { - // is already in pcache? - lfs_size_t diff = lfs_min(size, - lfs->cfg->prog_size - (off-pcache->off)); - memcpy(&pcache->buffer[off-pcache->off], data, diff); - - data += diff; - off += diff; - size -= diff; - - if (off % lfs->cfg->prog_size == 0) { - // eagerly flush out pcache if we fill up - int err = lfs_cache_flush(lfs, pcache, rcache); - if (err) { - return err; - } - } - - continue; - } - - // pcache must have been flushed, either by programming and - // entire block or manually flushing the pcache - LFS_ASSERT(pcache->block == 0xffffffff); - - if (off % lfs->cfg->prog_size == 0 && - size >= lfs->cfg->prog_size) { - // bypass pcache? - lfs_size_t diff = size - (size % lfs->cfg->prog_size); - int err = lfs->cfg->prog(lfs->cfg, block, off, data, diff); - if (err) { - return err; - } - - if (rcache) { - int res = lfs_cache_cmp(lfs, rcache, NULL, - block, off, data, diff); - if (res < 0) { - return res; - } - - if (!res) { - return LFS_ERR_CORRUPT; - } - } - - data += diff; - off += diff; - size -= diff; - continue; - } - - // prepare pcache, first condition can no longer fail - pcache->block = block; - pcache->off = off - (off % lfs->cfg->prog_size); - } - - return 0; -} - - -/// General lfs block device operations /// -static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) { - // if we ever do more than writes to alternating pairs, - // this may need to consider pcache - return lfs_cache_read(lfs, &lfs->rcache, NULL, - block, off, buffer, size); -} - -static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - return lfs_cache_prog(lfs, &lfs->pcache, NULL, - block, off, buffer, size); -} - -static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - return lfs_cache_cmp(lfs, &lfs->rcache, NULL, block, off, buffer, size); -} - -static int lfs_bd_crc(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, lfs_size_t size, uint32_t *crc) { - return lfs_cache_crc(lfs, &lfs->rcache, NULL, block, off, size, crc); -} - -static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { - return lfs->cfg->erase(lfs->cfg, block); -} - -static int lfs_bd_sync(lfs_t *lfs) { - lfs_cache_drop(lfs, &lfs->rcache); - - int err = lfs_cache_flush(lfs, &lfs->pcache, NULL); - if (err) { - return err; - } - - return lfs->cfg->sync(lfs->cfg); -} - - -/// Internal operations predeclared here /// -int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); -static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_dir_t *pdir); -static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2], - lfs_dir_t *parent, lfs_entry_t *entry); -static int lfs_moved(lfs_t *lfs, const void *e); -static int lfs_relocate(lfs_t *lfs, - const lfs_block_t oldpair[2], const lfs_block_t newpair[2]); -int lfs_deorphan(lfs_t *lfs); - - -/// Block allocator /// -static int lfs_alloc_lookahead(void *p, lfs_block_t block) { - lfs_t *lfs = p; - - lfs_block_t off = ((block - lfs->free.off) - + lfs->cfg->block_count) % lfs->cfg->block_count; - - if (off < lfs->free.size) { - lfs->free.buffer[off / 32] |= 1U << (off % 32); - } - - return 0; -} - -static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { - while (true) { - while (lfs->free.i != lfs->free.size) { - lfs_block_t off = lfs->free.i; - lfs->free.i += 1; - lfs->free.ack -= 1; - - if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { - // found a free block - *block = (lfs->free.off + off) % lfs->cfg->block_count; - - // eagerly find next off so an alloc ack can - // discredit old lookahead blocks - while (lfs->free.i != lfs->free.size && - (lfs->free.buffer[lfs->free.i / 32] - & (1U << (lfs->free.i % 32)))) { - lfs->free.i += 1; - lfs->free.ack -= 1; - } - - return 0; - } - } - - // check if we have looked at all blocks since last ack - if (lfs->free.ack == 0) { - LFS_WARN("No more free space %" PRIu32, - lfs->free.i + lfs->free.off); - return LFS_ERR_NOSPC; - } - - lfs->free.off = (lfs->free.off + lfs->free.size) - % lfs->cfg->block_count; - lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->free.ack); - lfs->free.i = 0; - - // find mask of free blocks from tree - memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8); - int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs); - if (err) { - return err; - } - } -} - -static void lfs_alloc_ack(lfs_t *lfs) { - lfs->free.ack = lfs->cfg->block_count; -} - - -/// Endian swapping functions /// -static void lfs_dir_fromle32(struct lfs_disk_dir *d) { - d->rev = lfs_fromle32(d->rev); - d->size = lfs_fromle32(d->size); - d->tail[0] = lfs_fromle32(d->tail[0]); - d->tail[1] = lfs_fromle32(d->tail[1]); -} - -static void lfs_dir_tole32(struct lfs_disk_dir *d) { - d->rev = lfs_tole32(d->rev); - d->size = lfs_tole32(d->size); - d->tail[0] = lfs_tole32(d->tail[0]); - d->tail[1] = lfs_tole32(d->tail[1]); -} - -static void lfs_entry_fromle32(struct lfs_disk_entry *d) { - d->u.dir[0] = lfs_fromle32(d->u.dir[0]); - d->u.dir[1] = lfs_fromle32(d->u.dir[1]); -} - -static void lfs_entry_tole32(struct lfs_disk_entry *d) { - d->u.dir[0] = lfs_tole32(d->u.dir[0]); - d->u.dir[1] = lfs_tole32(d->u.dir[1]); -} - -static void lfs_superblock_fromle32(struct lfs_disk_superblock *d) { - d->root[0] = lfs_fromle32(d->root[0]); - d->root[1] = lfs_fromle32(d->root[1]); - d->block_size = lfs_fromle32(d->block_size); - d->block_count = lfs_fromle32(d->block_count); - d->version = lfs_fromle32(d->version); -} - -static void lfs_superblock_tole32(struct lfs_disk_superblock *d) { - d->root[0] = lfs_tole32(d->root[0]); - d->root[1] = lfs_tole32(d->root[1]); - d->block_size = lfs_tole32(d->block_size); - d->block_count = lfs_tole32(d->block_count); - d->version = lfs_tole32(d->version); -} - - -/// Metadata pair and directory operations /// -static inline void lfs_pairswap(lfs_block_t pair[2]) { - lfs_block_t t = pair[0]; - pair[0] = pair[1]; - pair[1] = t; -} - -static inline bool lfs_pairisnull(const lfs_block_t pair[2]) { - return pair[0] == 0xffffffff || pair[1] == 0xffffffff; -} - -static inline int lfs_paircmp( - const lfs_block_t paira[2], - const lfs_block_t pairb[2]) { - return !(paira[0] == pairb[0] || paira[1] == pairb[1] || - paira[0] == pairb[1] || paira[1] == pairb[0]); -} - -static inline bool lfs_pairsync( - const lfs_block_t paira[2], - const lfs_block_t pairb[2]) { - return (paira[0] == pairb[0] && paira[1] == pairb[1]) || - (paira[0] == pairb[1] && paira[1] == pairb[0]); -} - -static inline lfs_size_t lfs_entry_size(const lfs_entry_t *entry) { - return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; -} - -static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) { - // allocate pair of dir blocks - for (int i = 0; i < 2; i++) { - int err = lfs_alloc(lfs, &dir->pair[i]); - if (err) { - return err; - } - } - - // rather than clobbering one of the blocks we just pretend - // the revision may be valid - int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->d.rev, 4); - if (err && err != LFS_ERR_CORRUPT) { - return err; - } - - if (err != LFS_ERR_CORRUPT) { - dir->d.rev = lfs_fromle32(dir->d.rev); - } - - // set defaults - dir->d.rev += 1; - dir->d.size = sizeof(dir->d)+4; - dir->d.tail[0] = 0xffffffff; - dir->d.tail[1] = 0xffffffff; - dir->off = sizeof(dir->d); - - // don't write out yet, let caller take care of that - return 0; -} - -static int lfs_dir_fetch(lfs_t *lfs, - lfs_dir_t *dir, const lfs_block_t pair[2]) { - // copy out pair, otherwise may be aliasing dir - const lfs_block_t tpair[2] = {pair[0], pair[1]}; - bool valid = false; - - // check both blocks for the most recent revision - for (int i = 0; i < 2; i++) { - struct lfs_disk_dir test; - int err = lfs_bd_read(lfs, tpair[i], 0, &test, sizeof(test)); - lfs_dir_fromle32(&test); - if (err) { - if (err == LFS_ERR_CORRUPT) { - continue; - } - return err; - } - - if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) { - continue; - } - - if ((0x7fffffff & test.size) < sizeof(test)+4 || - (0x7fffffff & test.size) > lfs->cfg->block_size) { - continue; - } - - uint32_t crc = 0xffffffff; - lfs_dir_tole32(&test); - lfs_crc(&crc, &test, sizeof(test)); - lfs_dir_fromle32(&test); - err = lfs_bd_crc(lfs, tpair[i], sizeof(test), - (0x7fffffff & test.size) - sizeof(test), &crc); - if (err) { - if (err == LFS_ERR_CORRUPT) { - continue; - } - return err; - } - - if (crc != 0) { - continue; - } - - valid = true; - - // setup dir in case it's valid - dir->pair[0] = tpair[(i+0) % 2]; - dir->pair[1] = tpair[(i+1) % 2]; - dir->off = sizeof(dir->d); - dir->d = test; - } - - if (!valid) { - LFS_ERROR("Corrupted dir pair at %" PRIu32 " %" PRIu32 , - tpair[0], tpair[1]); - return LFS_ERR_CORRUPT; - } - - return 0; -} - -struct lfs_region { - lfs_off_t oldoff; - lfs_size_t oldlen; - const void *newdata; - lfs_size_t newlen; -}; - -static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, - const struct lfs_region *regions, int count) { - // increment revision count - dir->d.rev += 1; - - // keep pairs in order such that pair[0] is most recent - lfs_pairswap(dir->pair); - for (int i = 0; i < count; i++) { - dir->d.size += regions[i].newlen - regions[i].oldlen; - } - - const lfs_block_t oldpair[2] = {dir->pair[0], dir->pair[1]}; - bool relocated = false; - - while (true) { - if (true) { - int err = lfs_bd_erase(lfs, dir->pair[0]); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - uint32_t crc = 0xffffffff; - lfs_dir_tole32(&dir->d); - lfs_crc(&crc, &dir->d, sizeof(dir->d)); - err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d)); - lfs_dir_fromle32(&dir->d); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - int i = 0; - lfs_off_t oldoff = sizeof(dir->d); - lfs_off_t newoff = sizeof(dir->d); - while (newoff < (0x7fffffff & dir->d.size)-4) { - if (i < count && regions[i].oldoff == oldoff) { - lfs_crc(&crc, regions[i].newdata, regions[i].newlen); - err = lfs_bd_prog(lfs, dir->pair[0], - newoff, regions[i].newdata, regions[i].newlen); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - oldoff += regions[i].oldlen; - newoff += regions[i].newlen; - i += 1; - } else { - uint8_t data; - err = lfs_bd_read(lfs, oldpair[1], oldoff, &data, 1); - if (err) { - return err; - } - - lfs_crc(&crc, &data, 1); - err = lfs_bd_prog(lfs, dir->pair[0], newoff, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - oldoff += 1; - newoff += 1; - } - } - - crc = lfs_tole32(crc); - err = lfs_bd_prog(lfs, dir->pair[0], newoff, &crc, 4); - crc = lfs_fromle32(crc); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - err = lfs_bd_sync(lfs); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // successful commit, check checksum to make sure - uint32_t ncrc = 0xffffffff; - err = lfs_bd_crc(lfs, dir->pair[0], 0, - (0x7fffffff & dir->d.size)-4, &ncrc); - if (err) { - return err; - } - - if (ncrc != crc) { - goto relocate; - } - } - - break; -relocate: - //commit was corrupted - LFS_DEBUG("Bad block at %" PRIu32, dir->pair[0]); - - // drop caches and prepare to relocate block - relocated = true; - lfs_cache_drop(lfs, &lfs->pcache); - - // can't relocate superblock, filesystem is now frozen - if (lfs_paircmp(oldpair, (const lfs_block_t[2]){0, 1}) == 0) { - LFS_WARN("Superblock %" PRIu32 " has become unwritable", - oldpair[0]); - return LFS_ERR_CORRUPT; - } - - // relocate half of pair - int err = lfs_alloc(lfs, &dir->pair[0]); - if (err) { - return err; - } - } - - if (relocated) { - // update references if we relocated - LFS_DEBUG("Relocating %" PRIu32 " %" PRIu32 " to %" PRIu32 " %" PRIu32, - oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); - int err = lfs_relocate(lfs, oldpair, dir->pair); - if (err) { - return err; - } - } - - // shift over any directories that are affected - for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { - if (lfs_paircmp(d->pair, dir->pair) == 0) { - d->pair[0] = dir->pair[0]; - d->pair[1] = dir->pair[1]; - } - } - - return 0; -} - -static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir, - lfs_entry_t *entry, const void *data) { - lfs_entry_tole32(&entry->d); - int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ - {entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)}, - {entry->off+sizeof(entry->d), entry->d.nlen, data, entry->d.nlen} - }, data ? 2 : 1); - lfs_entry_fromle32(&entry->d); - return err; -} - -static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, - lfs_entry_t *entry, const void *data) { - // check if we fit, if top bit is set we do not and move on - while (true) { - if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size) { - entry->off = dir->d.size - 4; - - lfs_entry_tole32(&entry->d); - int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ - {entry->off, 0, &entry->d, sizeof(entry->d)}, - {entry->off, 0, data, entry->d.nlen} - }, 2); - lfs_entry_fromle32(&entry->d); - return err; - } - - // we need to allocate a new dir block - if (!(0x80000000 & dir->d.size)) { - lfs_dir_t olddir = *dir; - int err = lfs_dir_alloc(lfs, dir); - if (err) { - return err; - } - - dir->d.tail[0] = olddir.d.tail[0]; - dir->d.tail[1] = olddir.d.tail[1]; - entry->off = dir->d.size - 4; - lfs_entry_tole32(&entry->d); - err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ - {entry->off, 0, &entry->d, sizeof(entry->d)}, - {entry->off, 0, data, entry->d.nlen} - }, 2); - lfs_entry_fromle32(&entry->d); - if (err) { - return err; - } - - olddir.d.size |= 0x80000000; - olddir.d.tail[0] = dir->pair[0]; - olddir.d.tail[1] = dir->pair[1]; - return lfs_dir_commit(lfs, &olddir, NULL, 0); - } - - int err = lfs_dir_fetch(lfs, dir, dir->d.tail); - if (err) { - return err; - } - } -} - -static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { - // check if we should just drop the directory block - if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 - + lfs_entry_size(entry)) { - lfs_dir_t pdir; - int res = lfs_pred(lfs, dir->pair, &pdir); - if (res < 0) { - return res; - } - - if (pdir.d.size & 0x80000000) { - pdir.d.size &= dir->d.size | 0x7fffffff; - pdir.d.tail[0] = dir->d.tail[0]; - pdir.d.tail[1] = dir->d.tail[1]; - return lfs_dir_commit(lfs, &pdir, NULL, 0); - } - } - - // shift out the entry - int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ - {entry->off, lfs_entry_size(entry), NULL, 0}, - }, 1); - if (err) { - return err; - } - - // shift over any files/directories that are affected - for (lfs_file_t *f = lfs->files; f; f = f->next) { - if (lfs_paircmp(f->pair, dir->pair) == 0) { - if (f->poff == entry->off) { - f->pair[0] = 0xffffffff; - f->pair[1] = 0xffffffff; - } else if (f->poff > entry->off) { - f->poff -= lfs_entry_size(entry); - } - } - } - - for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { - if (lfs_paircmp(d->pair, dir->pair) == 0) { - if (d->off > entry->off) { - d->off -= lfs_entry_size(entry); - d->pos -= lfs_entry_size(entry); - } - } - } - - return 0; -} - -static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { - while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { - if (!(0x80000000 & dir->d.size)) { - entry->off = dir->off; - return LFS_ERR_NOENT; - } - - int err = lfs_dir_fetch(lfs, dir, dir->d.tail); - if (err) { - return err; - } - - dir->off = sizeof(dir->d); - dir->pos += sizeof(dir->d) + 4; - } - - int err = lfs_bd_read(lfs, dir->pair[0], dir->off, - &entry->d, sizeof(entry->d)); - lfs_entry_fromle32(&entry->d); - if (err) { - return err; - } - - entry->off = dir->off; - dir->off += lfs_entry_size(entry); - dir->pos += lfs_entry_size(entry); - return 0; -} - -static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, - lfs_entry_t *entry, const char **path) { - const char *pathname = *path; - size_t pathlen; - entry->d.type = LFS_TYPE_DIR; - entry->d.elen = sizeof(entry->d) - 4; - entry->d.alen = 0; - entry->d.nlen = 0; - entry->d.u.dir[0] = lfs->root[0]; - entry->d.u.dir[1] = lfs->root[1]; - - while (true) { -nextname: - // skip slashes - pathname += strspn(pathname, "/"); - pathlen = strcspn(pathname, "/"); - - // skip '.' and root '..' - if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) || - (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) { - pathname += pathlen; - goto nextname; - } - - // skip if matched by '..' in name - const char *suffix = pathname + pathlen; - size_t sufflen; - int depth = 1; - while (true) { - suffix += strspn(suffix, "/"); - sufflen = strcspn(suffix, "/"); - if (sufflen == 0) { - break; - } - - if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { - depth -= 1; - if (depth == 0) { - pathname = suffix + sufflen; - goto nextname; - } - } else { - depth += 1; - } - - suffix += sufflen; - } - - // found path - if (pathname[0] == '\0') { - return 0; - } - - // update what we've found - *path = pathname; - - // continue on if we hit a directory - if (entry->d.type != LFS_TYPE_DIR) { - return LFS_ERR_NOTDIR; - } - - int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir); - if (err) { - return err; - } - - // find entry matching name - while (true) { - err = lfs_dir_next(lfs, dir, entry); - if (err) { - return err; - } - - if (((0x7f & entry->d.type) != LFS_TYPE_REG && - (0x7f & entry->d.type) != LFS_TYPE_DIR) || - entry->d.nlen != pathlen) { - continue; - } - - int res = lfs_bd_cmp(lfs, dir->pair[0], - entry->off + 4+entry->d.elen+entry->d.alen, - pathname, pathlen); - if (res < 0) { - return res; - } - - // found match - if (res) { - break; - } - } - - // check that entry has not been moved - if (!lfs->moving && entry->d.type & 0x80) { - int moved = lfs_moved(lfs, &entry->d.u); - if (moved < 0 || moved) { - return (moved < 0) ? moved : LFS_ERR_NOENT; - } - - entry->d.type &= ~0x80; - } - - // to next name - pathname += pathlen; - } -} - - -/// Top level directory operations /// -int lfs_mkdir(lfs_t *lfs, const char *path) { - // deorphan if we haven't yet, needed at most once after poweron - if (!lfs->deorphaned) { - int err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - - // fetch parent directory - lfs_dir_t cwd; - lfs_entry_t entry; - int err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) { - return err ? err : LFS_ERR_EXIST; - } - - // build up new directory - lfs_alloc_ack(lfs); - - lfs_dir_t dir; - err = lfs_dir_alloc(lfs, &dir); - if (err) { - return err; - } - dir.d.tail[0] = cwd.d.tail[0]; - dir.d.tail[1] = cwd.d.tail[1]; - - err = lfs_dir_commit(lfs, &dir, NULL, 0); - if (err) { - return err; - } - - entry.d.type = LFS_TYPE_DIR; - entry.d.elen = sizeof(entry.d) - 4; - entry.d.alen = 0; - entry.d.nlen = strlen(path); - entry.d.u.dir[0] = dir.pair[0]; - entry.d.u.dir[1] = dir.pair[1]; - - cwd.d.tail[0] = dir.pair[0]; - cwd.d.tail[1] = dir.pair[1]; - - err = lfs_dir_append(lfs, &cwd, &entry, path); - if (err) { - return err; - } - - lfs_alloc_ack(lfs); - return 0; -} - -int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { - dir->pair[0] = lfs->root[0]; - dir->pair[1] = lfs->root[1]; - - lfs_entry_t entry; - int err = lfs_dir_find(lfs, dir, &entry, &path); - if (err) { - return err; - } else if (entry.d.type != LFS_TYPE_DIR) { - return LFS_ERR_NOTDIR; - } - - err = lfs_dir_fetch(lfs, dir, entry.d.u.dir); - if (err) { - return err; - } - - // setup head dir - // special offset for '.' and '..' - dir->head[0] = dir->pair[0]; - dir->head[1] = dir->pair[1]; - dir->pos = sizeof(dir->d) - 2; - dir->off = sizeof(dir->d); - - // add to list of directories - dir->next = lfs->dirs; - lfs->dirs = dir; - - return 0; -} - -int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { - // remove from list of directories - for (lfs_dir_t **p = &lfs->dirs; *p; p = &(*p)->next) { - if (*p == dir) { - *p = dir->next; - break; - } - } - - return 0; -} - -int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { - memset(info, 0, sizeof(*info)); - - // special offset for '.' and '..' - if (dir->pos == sizeof(dir->d) - 2) { - info->type = LFS_TYPE_DIR; - strcpy(info->name, "."); - dir->pos += 1; - return 1; - } else if (dir->pos == sizeof(dir->d) - 1) { - info->type = LFS_TYPE_DIR; - strcpy(info->name, ".."); - dir->pos += 1; - return 1; - } - - lfs_entry_t entry; - while (true) { - int err = lfs_dir_next(lfs, dir, &entry); - if (err) { - return (err == LFS_ERR_NOENT) ? 0 : err; - } - - if ((0x7f & entry.d.type) != LFS_TYPE_REG && - (0x7f & entry.d.type) != LFS_TYPE_DIR) { - continue; - } - - // check that entry has not been moved - if (entry.d.type & 0x80) { - int moved = lfs_moved(lfs, &entry.d.u); - if (moved < 0) { - return moved; - } - - if (moved) { - continue; - } - - entry.d.type &= ~0x80; - } - - break; - } - - info->type = entry.d.type; - if (info->type == LFS_TYPE_REG) { - info->size = entry.d.u.file.size; - } - - int err = lfs_bd_read(lfs, dir->pair[0], - entry.off + 4+entry.d.elen+entry.d.alen, - info->name, entry.d.nlen); - if (err) { - return err; - } - - return 1; -} - -int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { - // simply walk from head dir - int err = lfs_dir_rewind(lfs, dir); - if (err) { - return err; - } - dir->pos = off; - - while (off > (0x7fffffff & dir->d.size)) { - off -= 0x7fffffff & dir->d.size; - if (!(0x80000000 & dir->d.size)) { - return LFS_ERR_INVAL; - } - - err = lfs_dir_fetch(lfs, dir, dir->d.tail); - if (err) { - return err; - } - } - - dir->off = off; - return 0; -} - -lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { - (void)lfs; - return dir->pos; -} - -int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { - // reload the head dir - int err = lfs_dir_fetch(lfs, dir, dir->head); - if (err) { - return err; - } - - dir->pair[0] = dir->head[0]; - dir->pair[1] = dir->head[1]; - dir->pos = sizeof(dir->d) - 2; - dir->off = sizeof(dir->d); - return 0; -} - - -/// File index list operations /// -static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) { - lfs_off_t size = *off; - lfs_off_t b = lfs->cfg->block_size - 2*4; - lfs_off_t i = size / b; - if (i == 0) { - return 0; - } - - i = (size - 4*(lfs_popc(i-1)+2)) / b; - *off = size - b*i - 4*lfs_popc(i); - return i; -} - -static int lfs_ctz_find(lfs_t *lfs, - lfs_cache_t *rcache, const lfs_cache_t *pcache, - lfs_block_t head, lfs_size_t size, - lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) { - if (size == 0) { - *block = 0xffffffff; - *off = 0; - return 0; - } - - lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); - lfs_off_t target = lfs_ctz_index(lfs, &pos); - - while (current > target) { - lfs_size_t skip = lfs_min( - lfs_npw2(current-target+1) - 1, - lfs_ctz(current)); - - int err = lfs_cache_read(lfs, rcache, pcache, head, 4*skip, &head, 4); - head = lfs_fromle32(head); - if (err) { - return err; - } - - LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count); - current -= 1 << skip; - } - - *block = head; - *off = pos; - return 0; -} - -static int lfs_ctz_extend(lfs_t *lfs, - lfs_cache_t *rcache, lfs_cache_t *pcache, - lfs_block_t head, lfs_size_t size, - lfs_block_t *block, lfs_off_t *off) { - while (true) { - // go ahead and grab a block - lfs_block_t nblock; - int err = lfs_alloc(lfs, &nblock); - if (err) { - return err; - } - LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count); - - if (true) { - err = lfs_bd_erase(lfs, nblock); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - if (size == 0) { - *block = nblock; - *off = 0; - return 0; - } - - size -= 1; - lfs_off_t index = lfs_ctz_index(lfs, &size); - size += 1; - - // just copy out the last block if it is incomplete - if (size != lfs->cfg->block_size) { - for (lfs_off_t i = 0; i < size; i++) { - uint8_t data; - err = lfs_cache_read(lfs, rcache, NULL, - head, i, &data, 1); - if (err) { - return err; - } - - err = lfs_cache_prog(lfs, pcache, rcache, - nblock, i, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - *block = nblock; - *off = size; - return 0; - } - - // append block - index += 1; - lfs_size_t skips = lfs_ctz(index) + 1; - - for (lfs_off_t i = 0; i < skips; i++) { - head = lfs_tole32(head); - err = lfs_cache_prog(lfs, pcache, rcache, - nblock, 4*i, &head, 4); - head = lfs_fromle32(head); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - if (i != skips-1) { - err = lfs_cache_read(lfs, rcache, NULL, - head, 4*i, &head, 4); - head = lfs_fromle32(head); - if (err) { - return err; - } - } - - LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count); - } - - *block = nblock; - *off = 4*skips; - return 0; - } - -relocate: - LFS_DEBUG("Bad block at %" PRIu32, nblock); - - // just clear cache and try a new block - lfs_cache_drop(lfs, &lfs->pcache); - } -} - -static int lfs_ctz_traverse(lfs_t *lfs, - lfs_cache_t *rcache, const lfs_cache_t *pcache, - lfs_block_t head, lfs_size_t size, - int (*cb)(void*, lfs_block_t), void *data) { - if (size == 0) { - return 0; - } - - lfs_off_t index = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); - - while (true) { - int err = cb(data, head); - if (err) { - return err; - } - - if (index == 0) { - return 0; - } - - lfs_block_t heads[2]; - int count = 2 - (index & 1); - err = lfs_cache_read(lfs, rcache, pcache, head, 0, &heads, count*4); - heads[0] = lfs_fromle32(heads[0]); - heads[1] = lfs_fromle32(heads[1]); - if (err) { - return err; - } - - for (int i = 0; i < count-1; i++) { - err = cb(data, heads[i]); - if (err) { - return err; - } - } - - head = heads[count-1]; - index -= count; - } -} - - -/// Top level file operations /// -int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, - const char *path, int flags, - const struct lfs_file_config *cfg) { - // deorphan if we haven't yet, needed at most once after poweron - if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) { - int err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - - // allocate entry for file if it doesn't exist - lfs_dir_t cwd; - lfs_entry_t entry; - int err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL)) { - return err; - } - - if (err == LFS_ERR_NOENT) { - if (!(flags & LFS_O_CREAT)) { - return LFS_ERR_NOENT; - } - - // create entry to remember name - entry.d.type = LFS_TYPE_REG; - entry.d.elen = sizeof(entry.d) - 4; - entry.d.alen = 0; - entry.d.nlen = strlen(path); - entry.d.u.file.head = 0xffffffff; - entry.d.u.file.size = 0; - err = lfs_dir_append(lfs, &cwd, &entry, path); - if (err) { - return err; - } - } else if (entry.d.type == LFS_TYPE_DIR) { - return LFS_ERR_ISDIR; - } else if (flags & LFS_O_EXCL) { - return LFS_ERR_EXIST; - } - - // setup file struct - file->cfg = cfg; - file->pair[0] = cwd.pair[0]; - file->pair[1] = cwd.pair[1]; - file->poff = entry.off; - file->head = entry.d.u.file.head; - file->size = entry.d.u.file.size; - file->flags = flags; - file->pos = 0; - - if (flags & LFS_O_TRUNC) { - if (file->size != 0) { - file->flags |= LFS_F_DIRTY; - } - file->head = 0xffffffff; - file->size = 0; - } - - // allocate buffer if needed - file->cache.block = 0xffffffff; - if (file->cfg && file->cfg->buffer) { - file->cache.buffer = file->cfg->buffer; - } else if (lfs->cfg->file_buffer) { - if (lfs->files) { - // already in use - return LFS_ERR_NOMEM; - } - file->cache.buffer = lfs->cfg->file_buffer; - } else if ((file->flags & 3) == LFS_O_RDONLY) { - file->cache.buffer = lfs_malloc(lfs->cfg->read_size); - if (!file->cache.buffer) { - return LFS_ERR_NOMEM; - } - } else { - file->cache.buffer = lfs_malloc(lfs->cfg->prog_size); - if (!file->cache.buffer) { - return LFS_ERR_NOMEM; - } - } - - // zero to avoid information leak - lfs_cache_drop(lfs, &file->cache); - if ((file->flags & 3) != LFS_O_RDONLY) { - lfs_cache_zero(lfs, &file->cache); - } - - // add to list of files - file->next = lfs->files; - lfs->files = file; - - return 0; -} - -int lfs_file_open(lfs_t *lfs, lfs_file_t *file, - const char *path, int flags) { - return lfs_file_opencfg(lfs, file, path, flags, NULL); -} - -int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { - int err = lfs_file_sync(lfs, file); - - // remove from list of files - for (lfs_file_t **p = &lfs->files; *p; p = &(*p)->next) { - if (*p == file) { - *p = file->next; - break; - } - } - - // clean up memory - if (!(file->cfg && file->cfg->buffer) && !lfs->cfg->file_buffer) { - lfs_free(file->cache.buffer); - } - - return err; -} - -static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { -relocate: - LFS_DEBUG("Bad block at %" PRIu32, file->block); - - // just relocate what exists into new block - lfs_block_t nblock; - int err = lfs_alloc(lfs, &nblock); - if (err) { - return err; - } - - err = lfs_bd_erase(lfs, nblock); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // either read from dirty cache or disk - for (lfs_off_t i = 0; i < file->off; i++) { - uint8_t data; - err = lfs_cache_read(lfs, &lfs->rcache, &file->cache, - file->block, i, &data, 1); - if (err) { - return err; - } - - err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, - nblock, i, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - // copy over new state of file - memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); - file->cache.block = lfs->pcache.block; - file->cache.off = lfs->pcache.off; - lfs_cache_zero(lfs, &lfs->pcache); - - file->block = nblock; - return 0; -} - -static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { - if (file->flags & LFS_F_READING) { - // just drop read cache - lfs_cache_drop(lfs, &file->cache); - file->flags &= ~LFS_F_READING; - } - - if (file->flags & LFS_F_WRITING) { - lfs_off_t pos = file->pos; - - // copy over anything after current branch - lfs_file_t orig = { - .head = file->head, - .size = file->size, - .flags = LFS_O_RDONLY, - .pos = file->pos, - .cache = lfs->rcache, - }; - lfs_cache_drop(lfs, &lfs->rcache); - - while (file->pos < file->size) { - // copy over a byte at a time, leave it up to caching - // to make this efficient - uint8_t data; - lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); - if (res < 0) { - return res; - } - - res = lfs_file_write(lfs, file, &data, 1); - if (res < 0) { - return res; - } - - // keep our reference to the rcache in sync - if (lfs->rcache.block != 0xffffffff) { - lfs_cache_drop(lfs, &orig.cache); - lfs_cache_drop(lfs, &lfs->rcache); - } - } - - // write out what we have - while (true) { - int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - break; -relocate: - err = lfs_file_relocate(lfs, file); - if (err) { - return err; - } - } - - // actual file updates - file->head = file->block; - file->size = file->pos; - file->flags &= ~LFS_F_WRITING; - file->flags |= LFS_F_DIRTY; - - file->pos = pos; - } - - return 0; -} - -int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { - int err = lfs_file_flush(lfs, file); - if (err) { - return err; - } - - if ((file->flags & LFS_F_DIRTY) && - !(file->flags & LFS_F_ERRED) && - !lfs_pairisnull(file->pair)) { - // update dir entry - lfs_dir_t cwd; - err = lfs_dir_fetch(lfs, &cwd, file->pair); - if (err) { - return err; - } - - lfs_entry_t entry = {.off = file->poff}; - err = lfs_bd_read(lfs, cwd.pair[0], entry.off, - &entry.d, sizeof(entry.d)); - lfs_entry_fromle32(&entry.d); - if (err) { - return err; - } - - LFS_ASSERT(entry.d.type == LFS_TYPE_REG); - entry.d.u.file.head = file->head; - entry.d.u.file.size = file->size; - - err = lfs_dir_update(lfs, &cwd, &entry, NULL); - if (err) { - return err; - } - - file->flags &= ~LFS_F_DIRTY; - } - - return 0; -} - -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, - void *buffer, lfs_size_t size) { - uint8_t *data = buffer; - lfs_size_t nsize = size; - - if ((file->flags & 3) == LFS_O_WRONLY) { - return LFS_ERR_BADF; - } - - if (file->flags & LFS_F_WRITING) { - // flush out any writes - int err = lfs_file_flush(lfs, file); - if (err) { - return err; - } - } - - if (file->pos >= file->size) { - // eof if past end - return 0; - } - - size = lfs_min(size, file->size - file->pos); - nsize = size; - - while (nsize > 0) { - // check if we need a new block - if (!(file->flags & LFS_F_READING) || - file->off == lfs->cfg->block_size) { - int err = lfs_ctz_find(lfs, &file->cache, NULL, - file->head, file->size, - file->pos, &file->block, &file->off); - if (err) { - return err; - } - - file->flags |= LFS_F_READING; - } - - // read as much as we can in current block - lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); - int err = lfs_cache_read(lfs, &file->cache, NULL, - file->block, file->off, data, diff); - if (err) { - return err; - } - - file->pos += diff; - file->off += diff; - data += diff; - nsize -= diff; - } - - return size; -} - -lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, - const void *buffer, lfs_size_t size) { - const uint8_t *data = buffer; - lfs_size_t nsize = size; - - if ((file->flags & 3) == LFS_O_RDONLY) { - return LFS_ERR_BADF; - } - - if (file->flags & LFS_F_READING) { - // drop any reads - int err = lfs_file_flush(lfs, file); - if (err) { - return err; - } - } - - if ((file->flags & LFS_O_APPEND) && file->pos < file->size) { - file->pos = file->size; - } - - if (file->pos + size > LFS_FILE_MAX) { - // larger than file limit? - return LFS_ERR_FBIG; - } - - if (!(file->flags & LFS_F_WRITING) && file->pos > file->size) { - // fill with zeros - lfs_off_t pos = file->pos; - file->pos = file->size; - - while (file->pos < pos) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); - if (res < 0) { - return res; - } - } - } - - while (nsize > 0) { - // check if we need a new block - if (!(file->flags & LFS_F_WRITING) || - file->off == lfs->cfg->block_size) { - if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { - // find out which block we're extending from - int err = lfs_ctz_find(lfs, &file->cache, NULL, - file->head, file->size, - file->pos-1, &file->block, &file->off); - if (err) { - file->flags |= LFS_F_ERRED; - return err; - } - - // mark cache as dirty since we may have read data into it - lfs_cache_zero(lfs, &file->cache); - } - - // extend file with new blocks - lfs_alloc_ack(lfs); - int err = lfs_ctz_extend(lfs, &lfs->rcache, &file->cache, - file->block, file->pos, - &file->block, &file->off); - if (err) { - file->flags |= LFS_F_ERRED; - return err; - } - - file->flags |= LFS_F_WRITING; - } - - // program as much as we can in current block - lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); - while (true) { - int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache, - file->block, file->off, data, diff); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - file->flags |= LFS_F_ERRED; - return err; - } - - break; -relocate: - err = lfs_file_relocate(lfs, file); - if (err) { - file->flags |= LFS_F_ERRED; - return err; - } - } - - file->pos += diff; - file->off += diff; - data += diff; - nsize -= diff; - - lfs_alloc_ack(lfs); - } - - file->flags &= ~LFS_F_ERRED; - return size; -} - -lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, - lfs_soff_t off, int whence) { - // write out everything beforehand, may be noop if rdonly - int err = lfs_file_flush(lfs, file); - if (err) { - return err; - } - - // find new pos - lfs_soff_t npos = file->pos; - if (whence == LFS_SEEK_SET) { - npos = off; - } else if (whence == LFS_SEEK_CUR) { - npos = file->pos + off; - } else if (whence == LFS_SEEK_END) { - npos = file->size + off; - } - - if (npos < 0 || npos > LFS_FILE_MAX) { - // file position out of range - return LFS_ERR_INVAL; - } - - // update pos - file->pos = npos; - return npos; -} - -int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { - if ((file->flags & 3) == LFS_O_RDONLY) { - return LFS_ERR_BADF; - } - - lfs_off_t oldsize = lfs_file_size(lfs, file); - if (size < oldsize) { - // need to flush since directly changing metadata - int err = lfs_file_flush(lfs, file); - if (err) { - return err; - } - - // lookup new head in ctz skip list - err = lfs_ctz_find(lfs, &file->cache, NULL, - file->head, file->size, - size, &file->head, &(lfs_off_t){0}); - if (err) { - return err; - } - - file->size = size; - file->flags |= LFS_F_DIRTY; - } else if (size > oldsize) { - lfs_off_t pos = file->pos; - - // flush+seek if not already at end - if (file->pos != oldsize) { - int err = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); - if (err < 0) { - return err; - } - } - - // fill with zeros - while (file->pos < size) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); - if (res < 0) { - return res; - } - } - - // restore pos - int err = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); - if (err < 0) { - return err; - } - } - - return 0; -} - -lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { - (void)lfs; - return file->pos; -} - -int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET); - if (res < 0) { - return res; - } - - return 0; -} - -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { - (void)lfs; - if (file->flags & LFS_F_WRITING) { - return lfs_max(file->pos, file->size); - } else { - return file->size; - } -} - - -/// General fs operations /// -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { - lfs_dir_t cwd; - lfs_entry_t entry; - int err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err) { - return err; - } - - memset(info, 0, sizeof(*info)); - info->type = entry.d.type; - if (info->type == LFS_TYPE_REG) { - info->size = entry.d.u.file.size; - } - - if (lfs_paircmp(entry.d.u.dir, lfs->root) == 0) { - strcpy(info->name, "/"); - } else { - err = lfs_bd_read(lfs, cwd.pair[0], - entry.off + 4+entry.d.elen+entry.d.alen, - info->name, entry.d.nlen); - if (err) { - return err; - } - } - - return 0; -} - -int lfs_remove(lfs_t *lfs, const char *path) { - // deorphan if we haven't yet, needed at most once after poweron - if (!lfs->deorphaned) { - int err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - - lfs_dir_t cwd; - lfs_entry_t entry; - int err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err) { - return err; - } - - lfs_dir_t dir; - if (entry.d.type == LFS_TYPE_DIR) { - // must be empty before removal, checking size - // without masking top bit checks for any case where - // dir is not empty - err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir); - if (err) { - return err; - } else if (dir.d.size != sizeof(dir.d)+4) { - return LFS_ERR_NOTEMPTY; - } - } - - // remove the entry - err = lfs_dir_remove(lfs, &cwd, &entry); - if (err) { - return err; - } - - // if we were a directory, find pred, replace tail - if (entry.d.type == LFS_TYPE_DIR) { - int res = lfs_pred(lfs, dir.pair, &cwd); - if (res < 0) { - return res; - } - - LFS_ASSERT(res); // must have pred - cwd.d.tail[0] = dir.d.tail[0]; - cwd.d.tail[1] = dir.d.tail[1]; - - err = lfs_dir_commit(lfs, &cwd, NULL, 0); - if (err) { - return err; - } - } - - return 0; -} - -int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { - // deorphan if we haven't yet, needed at most once after poweron - if (!lfs->deorphaned) { - int err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - - // find old entry - lfs_dir_t oldcwd; - lfs_entry_t oldentry; - int err = lfs_dir_find(lfs, &oldcwd, &oldentry, &(const char *){oldpath}); - if (err) { - return err; - } - - // mark as moving - oldentry.d.type |= 0x80; - err = lfs_dir_update(lfs, &oldcwd, &oldentry, NULL); - if (err) { - return err; - } - - // allocate new entry - lfs_dir_t newcwd; - lfs_entry_t preventry; - err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath); - if (err && (err != LFS_ERR_NOENT || strchr(newpath, '/') != NULL)) { - return err; - } - - // must have same type - bool prevexists = (err != LFS_ERR_NOENT); - if (prevexists && preventry.d.type != (0x7f & oldentry.d.type)) { - return LFS_ERR_ISDIR; - } - - lfs_dir_t dir; - if (prevexists && preventry.d.type == LFS_TYPE_DIR) { - // must be empty before removal, checking size - // without masking top bit checks for any case where - // dir is not empty - err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir); - if (err) { - return err; - } else if (dir.d.size != sizeof(dir.d)+4) { - return LFS_ERR_NOTEMPTY; - } - } - - // move to new location - lfs_entry_t newentry = preventry; - newentry.d = oldentry.d; - newentry.d.type &= ~0x80; - newentry.d.nlen = strlen(newpath); - - if (prevexists) { - err = lfs_dir_update(lfs, &newcwd, &newentry, newpath); - if (err) { - return err; - } - } else { - err = lfs_dir_append(lfs, &newcwd, &newentry, newpath); - if (err) { - return err; - } - } - - // fetch old pair again in case dir block changed - lfs->moving = true; - err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath); - if (err) { - return err; - } - lfs->moving = false; - - // remove old entry - err = lfs_dir_remove(lfs, &oldcwd, &oldentry); - if (err) { - return err; - } - - // if we were a directory, find pred, replace tail - if (prevexists && preventry.d.type == LFS_TYPE_DIR) { - int res = lfs_pred(lfs, dir.pair, &newcwd); - if (res < 0) { - return res; - } - - LFS_ASSERT(res); // must have pred - newcwd.d.tail[0] = dir.d.tail[0]; - newcwd.d.tail[1] = dir.d.tail[1]; - - err = lfs_dir_commit(lfs, &newcwd, NULL, 0); - if (err) { - return err; - } - } - - return 0; -} - - -/// Filesystem operations /// -static void lfs_deinit(lfs_t *lfs) { - // free allocated memory - if (!lfs->cfg->read_buffer) { - lfs_free(lfs->rcache.buffer); - } - - if (!lfs->cfg->prog_buffer) { - lfs_free(lfs->pcache.buffer); - } - - if (!lfs->cfg->lookahead_buffer) { - lfs_free(lfs->free.buffer); - } -} - -static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { - lfs->cfg = cfg; - - // setup read cache - if (lfs->cfg->read_buffer) { - lfs->rcache.buffer = lfs->cfg->read_buffer; - } else { - lfs->rcache.buffer = lfs_malloc(lfs->cfg->read_size); - if (!lfs->rcache.buffer) { - goto cleanup; - } - } - - // setup program cache - if (lfs->cfg->prog_buffer) { - lfs->pcache.buffer = lfs->cfg->prog_buffer; - } else { - lfs->pcache.buffer = lfs_malloc(lfs->cfg->prog_size); - if (!lfs->pcache.buffer) { - goto cleanup; - } - } - - // zero to avoid information leaks - lfs_cache_zero(lfs, &lfs->pcache); - lfs_cache_drop(lfs, &lfs->rcache); - - // setup lookahead, round down to nearest 32-bits - LFS_ASSERT(lfs->cfg->lookahead % 32 == 0); - LFS_ASSERT(lfs->cfg->lookahead > 0); - if (lfs->cfg->lookahead_buffer) { - lfs->free.buffer = lfs->cfg->lookahead_buffer; - } else { - lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead/8); - if (!lfs->free.buffer) { - goto cleanup; - } - } - - // check that program and read sizes are multiples of the block size - LFS_ASSERT(lfs->cfg->prog_size % lfs->cfg->read_size == 0); - LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->prog_size == 0); - - // check that the block size is large enough to fit ctz pointers - LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) - <= lfs->cfg->block_size); - - // setup default state - lfs->root[0] = 0xffffffff; - lfs->root[1] = 0xffffffff; - lfs->files = NULL; - lfs->dirs = NULL; - lfs->deorphaned = false; - lfs->moving = false; - - return 0; - -cleanup: - lfs_deinit(lfs); - return LFS_ERR_NOMEM; -} - -int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { - int err = 0; - if (true) { - err = lfs_init(lfs, cfg); - if (err) { - return err; - } - - // create free lookahead - memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8); - lfs->free.off = 0; - lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count); - lfs->free.i = 0; - lfs_alloc_ack(lfs); - - // create superblock dir - lfs_dir_t superdir; - err = lfs_dir_alloc(lfs, &superdir); - if (err) { - goto cleanup; - } - - // write root directory - lfs_dir_t root; - err = lfs_dir_alloc(lfs, &root); - if (err) { - goto cleanup; - } - - err = lfs_dir_commit(lfs, &root, NULL, 0); - if (err) { - goto cleanup; - } - - lfs->root[0] = root.pair[0]; - lfs->root[1] = root.pair[1]; - - // write superblocks - lfs_superblock_t superblock = { - .off = sizeof(superdir.d), - .d.type = LFS_TYPE_SUPERBLOCK, - .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4, - .d.nlen = sizeof(superblock.d.magic), - .d.version = LFS_DISK_VERSION, - .d.magic = {"littlefs"}, - .d.block_size = lfs->cfg->block_size, - .d.block_count = lfs->cfg->block_count, - .d.root = {lfs->root[0], lfs->root[1]}, - }; - superdir.d.tail[0] = root.pair[0]; - superdir.d.tail[1] = root.pair[1]; - superdir.d.size = sizeof(superdir.d) + sizeof(superblock.d) + 4; - - // write both pairs to be safe - lfs_superblock_tole32(&superblock.d); - bool valid = false; - for (int i = 0; i < 2; i++) { - err = lfs_dir_commit(lfs, &superdir, (struct lfs_region[]){ - {sizeof(superdir.d), sizeof(superblock.d), - &superblock.d, sizeof(superblock.d)} - }, 1); - if (err && err != LFS_ERR_CORRUPT) { - goto cleanup; - } - - valid = valid || !err; - } - - if (!valid) { - err = LFS_ERR_CORRUPT; - goto cleanup; - } - - // sanity check that fetch works - err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); - if (err) { - goto cleanup; - } - - lfs_alloc_ack(lfs); - } - -cleanup: - lfs_deinit(lfs); - return err; -} - -int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { - int err = 0; - if (true) { - err = lfs_init(lfs, cfg); - if (err) { - return err; - } - - // setup free lookahead - lfs->free.off = 0; - lfs->free.size = 0; - lfs->free.i = 0; - lfs_alloc_ack(lfs); - - // load superblock - lfs_dir_t dir; - lfs_superblock_t superblock; - err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); - if (err && err != LFS_ERR_CORRUPT) { - goto cleanup; - } - - if (!err) { - err = lfs_bd_read(lfs, dir.pair[0], sizeof(dir.d), - &superblock.d, sizeof(superblock.d)); - lfs_superblock_fromle32(&superblock.d); - if (err) { - goto cleanup; - } - - lfs->root[0] = superblock.d.root[0]; - lfs->root[1] = superblock.d.root[1]; - } - - if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { - LFS_ERROR("Invalid superblock at %d %d", 0, 1); - err = LFS_ERR_CORRUPT; - goto cleanup; - } - - uint16_t major_version = (0xffff & (superblock.d.version >> 16)); - uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); - if ((major_version != LFS_DISK_VERSION_MAJOR || - minor_version > LFS_DISK_VERSION_MINOR)) { - LFS_ERROR("Invalid version %d.%d", major_version, minor_version); - err = LFS_ERR_INVAL; - goto cleanup; - } - - return 0; - } - -cleanup: - - lfs_deinit(lfs); - return err; -} - -int lfs_unmount(lfs_t *lfs) { - lfs_deinit(lfs); - return 0; -} - - -/// Littlefs specific operations /// -int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { - if (lfs_pairisnull(lfs->root)) { - return 0; - } - - // iterate over metadata pairs - lfs_dir_t dir; - lfs_entry_t entry; - lfs_block_t cwd[2] = {0, 1}; - - while (true) { - for (int i = 0; i < 2; i++) { - int err = cb(data, cwd[i]); - if (err) { - return err; - } - } - - int err = lfs_dir_fetch(lfs, &dir, cwd); - if (err) { - return err; - } - - // iterate over contents - while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { - err = lfs_bd_read(lfs, dir.pair[0], dir.off, - &entry.d, sizeof(entry.d)); - lfs_entry_fromle32(&entry.d); - if (err) { - return err; - } - - dir.off += lfs_entry_size(&entry); - if ((0x70 & entry.d.type) == (0x70 & LFS_TYPE_REG)) { - err = lfs_ctz_traverse(lfs, &lfs->rcache, NULL, - entry.d.u.file.head, entry.d.u.file.size, cb, data); - if (err) { - return err; - } - } - } - - cwd[0] = dir.d.tail[0]; - cwd[1] = dir.d.tail[1]; - - if (lfs_pairisnull(cwd)) { - break; - } - } - - // iterate over any open files - for (lfs_file_t *f = lfs->files; f; f = f->next) { - if (f->flags & LFS_F_DIRTY) { - int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache, - f->head, f->size, cb, data); - if (err) { - return err; - } - } - - if (f->flags & LFS_F_WRITING) { - int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache, - f->block, f->pos, cb, data); - if (err) { - return err; - } - } - } - - return 0; -} - -static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_dir_t *pdir) { - if (lfs_pairisnull(lfs->root)) { - return 0; - } - - // iterate over all directory directory entries - int err = lfs_dir_fetch(lfs, pdir, (const lfs_block_t[2]){0, 1}); - if (err) { - return err; - } - - while (!lfs_pairisnull(pdir->d.tail)) { - if (lfs_paircmp(pdir->d.tail, dir) == 0) { - return true; - } - - err = lfs_dir_fetch(lfs, pdir, pdir->d.tail); - if (err) { - return err; - } - } - - return false; -} - -static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2], - lfs_dir_t *parent, lfs_entry_t *entry) { - if (lfs_pairisnull(lfs->root)) { - return 0; - } - - parent->d.tail[0] = 0; - parent->d.tail[1] = 1; - - // iterate over all directory directory entries - while (!lfs_pairisnull(parent->d.tail)) { - int err = lfs_dir_fetch(lfs, parent, parent->d.tail); - if (err) { - return err; - } - - while (true) { - err = lfs_dir_next(lfs, parent, entry); - if (err && err != LFS_ERR_NOENT) { - return err; - } - - if (err == LFS_ERR_NOENT) { - break; - } - - if (((0x70 & entry->d.type) == (0x70 & LFS_TYPE_DIR)) && - lfs_paircmp(entry->d.u.dir, dir) == 0) { - return true; - } - } - } - - return false; -} - -static int lfs_moved(lfs_t *lfs, const void *e) { - if (lfs_pairisnull(lfs->root)) { - return 0; - } - - // skip superblock - lfs_dir_t cwd; - int err = lfs_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){0, 1}); - if (err) { - return err; - } - - // iterate over all directory directory entries - lfs_entry_t entry; - while (!lfs_pairisnull(cwd.d.tail)) { - err = lfs_dir_fetch(lfs, &cwd, cwd.d.tail); - if (err) { - return err; - } - - while (true) { - err = lfs_dir_next(lfs, &cwd, &entry); - if (err && err != LFS_ERR_NOENT) { - return err; - } - - if (err == LFS_ERR_NOENT) { - break; - } - - if (!(0x80 & entry.d.type) && - memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { - return true; - } - } - } - - return false; -} - -static int lfs_relocate(lfs_t *lfs, - const lfs_block_t oldpair[2], const lfs_block_t newpair[2]) { - // find parent - lfs_dir_t parent; - lfs_entry_t entry; - int res = lfs_parent(lfs, oldpair, &parent, &entry); - if (res < 0) { - return res; - } - - if (res) { - // update disk, this creates a desync - entry.d.u.dir[0] = newpair[0]; - entry.d.u.dir[1] = newpair[1]; - - int err = lfs_dir_update(lfs, &parent, &entry, NULL); - if (err) { - return err; - } - - // update internal root - if (lfs_paircmp(oldpair, lfs->root) == 0) { - LFS_DEBUG("Relocating root %" PRIu32 " %" PRIu32, - newpair[0], newpair[1]); - lfs->root[0] = newpair[0]; - lfs->root[1] = newpair[1]; - } - - // clean up bad block, which should now be a desync - return lfs_deorphan(lfs); - } - - // find pred - res = lfs_pred(lfs, oldpair, &parent); - if (res < 0) { - return res; - } - - if (res) { - // just replace bad pair, no desync can occur - parent.d.tail[0] = newpair[0]; - parent.d.tail[1] = newpair[1]; - - return lfs_dir_commit(lfs, &parent, NULL, 0); - } - - // couldn't find dir, must be new - return 0; -} - -int lfs_deorphan(lfs_t *lfs) { - lfs->deorphaned = true; - - if (lfs_pairisnull(lfs->root)) { - return 0; - } - - lfs_dir_t pdir = {.d.size = 0x80000000}; - lfs_dir_t cwd = {.d.tail[0] = 0, .d.tail[1] = 1}; - - // iterate over all directory directory entries - for (lfs_size_t i = 0; i < lfs->cfg->block_count; i++) { - if (lfs_pairisnull(cwd.d.tail)) { - return 0; - } - - int err = lfs_dir_fetch(lfs, &cwd, cwd.d.tail); - if (err) { - return err; - } - - // check head blocks for orphans - if (!(0x80000000 & pdir.d.size)) { - // check if we have a parent - lfs_dir_t parent; - lfs_entry_t entry; - int res = lfs_parent(lfs, pdir.d.tail, &parent, &entry); - if (res < 0) { - return res; - } - - if (!res) { - // we are an orphan - LFS_DEBUG("Found orphan %" PRIu32 " %" PRIu32, - pdir.d.tail[0], pdir.d.tail[1]); - - pdir.d.tail[0] = cwd.d.tail[0]; - pdir.d.tail[1] = cwd.d.tail[1]; - - err = lfs_dir_commit(lfs, &pdir, NULL, 0); - if (err) { - return err; - } - - return 0; - } - - if (!lfs_pairsync(entry.d.u.dir, pdir.d.tail)) { - // we have desynced - LFS_DEBUG("Found desync %" PRIu32 " %" PRIu32, - entry.d.u.dir[0], entry.d.u.dir[1]); - - pdir.d.tail[0] = entry.d.u.dir[0]; - pdir.d.tail[1] = entry.d.u.dir[1]; - - err = lfs_dir_commit(lfs, &pdir, NULL, 0); - if (err) { - return err; - } - - return 0; - } - } - - // check entries for moves - lfs_entry_t entry; - while (true) { - err = lfs_dir_next(lfs, &cwd, &entry); - if (err && err != LFS_ERR_NOENT) { - return err; - } - - if (err == LFS_ERR_NOENT) { - break; - } - - // found moved entry - if (entry.d.type & 0x80) { - int moved = lfs_moved(lfs, &entry.d.u); - if (moved < 0) { - return moved; - } - - if (moved) { - LFS_DEBUG("Found move %" PRIu32 " %" PRIu32, - entry.d.u.dir[0], entry.d.u.dir[1]); - err = lfs_dir_remove(lfs, &cwd, &entry); - if (err) { - return err; - } - } else { - LFS_DEBUG("Found partial move %" PRIu32 " %" PRIu32, - entry.d.u.dir[0], entry.d.u.dir[1]); - entry.d.type &= ~0x80; - err = lfs_dir_update(lfs, &cwd, &entry, NULL); - if (err) { - return err; - } - } - } - } - - memcpy(&pdir, &cwd, sizeof(pdir)); - } - - // If we reached here, we have more directory pairs than blocks in the - // filesystem... So something must be horribly wrong - return LFS_ERR_CORRUPT; -} diff --git a/lfs1.c b/lfs1.c new file mode 100644 index 0000000..6a3fd67 --- /dev/null +++ b/lfs1.c @@ -0,0 +1,2583 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs1.h" +#include "lfs1_util.h" + +#include + + +/// Caching block device operations /// +static int lfs1_cache_read(lfs1_t *lfs1, lfs1_cache_t *rcache, + const lfs1_cache_t *pcache, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size) { + uint8_t *data = buffer; + LFS1_ASSERT(block < lfs1->cfg->block_count); + + while (size > 0) { + if (pcache && block == pcache->block && off >= pcache->off && + off < pcache->off + lfs1->cfg->prog_size) { + // is already in pcache? + lfs1_size_t diff = lfs1_min(size, + lfs1->cfg->prog_size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + if (block == rcache->block && off >= rcache->off && + off < rcache->off + lfs1->cfg->read_size) { + // is already in rcache? + lfs1_size_t diff = lfs1_min(size, + lfs1->cfg->read_size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + if (off % lfs1->cfg->read_size == 0 && size >= lfs1->cfg->read_size) { + // bypass cache? + lfs1_size_t diff = size - (size % lfs1->cfg->read_size); + int err = lfs1->cfg->read(lfs1->cfg, block, off, data, diff); + if (err) { + return err; + } + + data += diff; + off += diff; + size -= diff; + continue; + } + + // load to cache, first condition can no longer fail + rcache->block = block; + rcache->off = off - (off % lfs1->cfg->read_size); + int err = lfs1->cfg->read(lfs1->cfg, rcache->block, + rcache->off, rcache->buffer, lfs1->cfg->read_size); + if (err) { + return err; + } + } + + return 0; +} + +static int lfs1_cache_cmp(lfs1_t *lfs1, lfs1_cache_t *rcache, + const lfs1_cache_t *pcache, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + const uint8_t *data = buffer; + + for (lfs1_off_t i = 0; i < size; i++) { + uint8_t c; + int err = lfs1_cache_read(lfs1, rcache, pcache, + block, off+i, &c, 1); + if (err) { + return err; + } + + if (c != data[i]) { + return false; + } + } + + return true; +} + +static int lfs1_cache_crc(lfs1_t *lfs1, lfs1_cache_t *rcache, + const lfs1_cache_t *pcache, lfs1_block_t block, + lfs1_off_t off, lfs1_size_t size, uint32_t *crc) { + for (lfs1_off_t i = 0; i < size; i++) { + uint8_t c; + int err = lfs1_cache_read(lfs1, rcache, pcache, + block, off+i, &c, 1); + if (err) { + return err; + } + + lfs1_crc(crc, &c, 1); + } + + return 0; +} + +static inline void lfs1_cache_drop(lfs1_t *lfs1, lfs1_cache_t *rcache) { + // do not zero, cheaper if cache is readonly or only going to be + // written with identical data (during relocates) + (void)lfs1; + rcache->block = 0xffffffff; +} + +static inline void lfs1_cache_zero(lfs1_t *lfs1, lfs1_cache_t *pcache) { + // zero to avoid information leak + memset(pcache->buffer, 0xff, lfs1->cfg->prog_size); + pcache->block = 0xffffffff; +} + +static int lfs1_cache_flush(lfs1_t *lfs1, + lfs1_cache_t *pcache, lfs1_cache_t *rcache) { + if (pcache->block != 0xffffffff) { + int err = lfs1->cfg->prog(lfs1->cfg, pcache->block, + pcache->off, pcache->buffer, lfs1->cfg->prog_size); + if (err) { + return err; + } + + if (rcache) { + int res = lfs1_cache_cmp(lfs1, rcache, NULL, pcache->block, + pcache->off, pcache->buffer, lfs1->cfg->prog_size); + if (res < 0) { + return res; + } + + if (!res) { + return LFS1_ERR_CORRUPT; + } + } + + lfs1_cache_zero(lfs1, pcache); + } + + return 0; +} + +static int lfs1_cache_prog(lfs1_t *lfs1, lfs1_cache_t *pcache, + lfs1_cache_t *rcache, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + const uint8_t *data = buffer; + LFS1_ASSERT(block < lfs1->cfg->block_count); + + while (size > 0) { + if (block == pcache->block && off >= pcache->off && + off < pcache->off + lfs1->cfg->prog_size) { + // is already in pcache? + lfs1_size_t diff = lfs1_min(size, + lfs1->cfg->prog_size - (off-pcache->off)); + memcpy(&pcache->buffer[off-pcache->off], data, diff); + + data += diff; + off += diff; + size -= diff; + + if (off % lfs1->cfg->prog_size == 0) { + // eagerly flush out pcache if we fill up + int err = lfs1_cache_flush(lfs1, pcache, rcache); + if (err) { + return err; + } + } + + continue; + } + + // pcache must have been flushed, either by programming and + // entire block or manually flushing the pcache + LFS1_ASSERT(pcache->block == 0xffffffff); + + if (off % lfs1->cfg->prog_size == 0 && + size >= lfs1->cfg->prog_size) { + // bypass pcache? + lfs1_size_t diff = size - (size % lfs1->cfg->prog_size); + int err = lfs1->cfg->prog(lfs1->cfg, block, off, data, diff); + if (err) { + return err; + } + + if (rcache) { + int res = lfs1_cache_cmp(lfs1, rcache, NULL, + block, off, data, diff); + if (res < 0) { + return res; + } + + if (!res) { + return LFS1_ERR_CORRUPT; + } + } + + data += diff; + off += diff; + size -= diff; + continue; + } + + // prepare pcache, first condition can no longer fail + pcache->block = block; + pcache->off = off - (off % lfs1->cfg->prog_size); + } + + return 0; +} + + +/// General lfs1 block device operations /// +static int lfs1_bd_read(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size) { + // if we ever do more than writes to alternating pairs, + // this may need to consider pcache + return lfs1_cache_read(lfs1, &lfs1->rcache, NULL, + block, off, buffer, size); +} + +static int lfs1_bd_prog(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + return lfs1_cache_prog(lfs1, &lfs1->pcache, NULL, + block, off, buffer, size); +} + +static int lfs1_bd_cmp(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size) { + return lfs1_cache_cmp(lfs1, &lfs1->rcache, NULL, block, off, buffer, size); +} + +static int lfs1_bd_crc(lfs1_t *lfs1, lfs1_block_t block, + lfs1_off_t off, lfs1_size_t size, uint32_t *crc) { + return lfs1_cache_crc(lfs1, &lfs1->rcache, NULL, block, off, size, crc); +} + +static int lfs1_bd_erase(lfs1_t *lfs1, lfs1_block_t block) { + return lfs1->cfg->erase(lfs1->cfg, block); +} + +static int lfs1_bd_sync(lfs1_t *lfs1) { + lfs1_cache_drop(lfs1, &lfs1->rcache); + + int err = lfs1_cache_flush(lfs1, &lfs1->pcache, NULL); + if (err) { + return err; + } + + return lfs1->cfg->sync(lfs1->cfg); +} + + +/// Internal operations predeclared here /// +int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data); +static int lfs1_pred(lfs1_t *lfs1, const lfs1_block_t dir[2], lfs1_dir_t *pdir); +static int lfs1_parent(lfs1_t *lfs1, const lfs1_block_t dir[2], + lfs1_dir_t *parent, lfs1_entry_t *entry); +static int lfs1_moved(lfs1_t *lfs1, const void *e); +static int lfs1_relocate(lfs1_t *lfs1, + const lfs1_block_t oldpair[2], const lfs1_block_t newpair[2]); +int lfs1_deorphan(lfs1_t *lfs1); + + +/// Block allocator /// +static int lfs1_alloc_lookahead(void *p, lfs1_block_t block) { + lfs1_t *lfs1 = p; + + lfs1_block_t off = ((block - lfs1->free.off) + + lfs1->cfg->block_count) % lfs1->cfg->block_count; + + if (off < lfs1->free.size) { + lfs1->free.buffer[off / 32] |= 1U << (off % 32); + } + + return 0; +} + +static int lfs1_alloc(lfs1_t *lfs1, lfs1_block_t *block) { + while (true) { + while (lfs1->free.i != lfs1->free.size) { + lfs1_block_t off = lfs1->free.i; + lfs1->free.i += 1; + lfs1->free.ack -= 1; + + if (!(lfs1->free.buffer[off / 32] & (1U << (off % 32)))) { + // found a free block + *block = (lfs1->free.off + off) % lfs1->cfg->block_count; + + // eagerly find next off so an alloc ack can + // discredit old lookahead blocks + while (lfs1->free.i != lfs1->free.size && + (lfs1->free.buffer[lfs1->free.i / 32] + & (1U << (lfs1->free.i % 32)))) { + lfs1->free.i += 1; + lfs1->free.ack -= 1; + } + + return 0; + } + } + + // check if we have looked at all blocks since last ack + if (lfs1->free.ack == 0) { + LFS1_WARN("No more free space %" PRIu32, + lfs1->free.i + lfs1->free.off); + return LFS1_ERR_NOSPC; + } + + lfs1->free.off = (lfs1->free.off + lfs1->free.size) + % lfs1->cfg->block_count; + lfs1->free.size = lfs1_min(lfs1->cfg->lookahead, lfs1->free.ack); + lfs1->free.i = 0; + + // find mask of free blocks from tree + memset(lfs1->free.buffer, 0, lfs1->cfg->lookahead/8); + int err = lfs1_traverse(lfs1, lfs1_alloc_lookahead, lfs1); + if (err) { + return err; + } + } +} + +static void lfs1_alloc_ack(lfs1_t *lfs1) { + lfs1->free.ack = lfs1->cfg->block_count; +} + + +/// Endian swapping functions /// +static void lfs1_dir_fromle32(struct lfs1_disk_dir *d) { + d->rev = lfs1_fromle32(d->rev); + d->size = lfs1_fromle32(d->size); + d->tail[0] = lfs1_fromle32(d->tail[0]); + d->tail[1] = lfs1_fromle32(d->tail[1]); +} + +static void lfs1_dir_tole32(struct lfs1_disk_dir *d) { + d->rev = lfs1_tole32(d->rev); + d->size = lfs1_tole32(d->size); + d->tail[0] = lfs1_tole32(d->tail[0]); + d->tail[1] = lfs1_tole32(d->tail[1]); +} + +static void lfs1_entry_fromle32(struct lfs1_disk_entry *d) { + d->u.dir[0] = lfs1_fromle32(d->u.dir[0]); + d->u.dir[1] = lfs1_fromle32(d->u.dir[1]); +} + +static void lfs1_entry_tole32(struct lfs1_disk_entry *d) { + d->u.dir[0] = lfs1_tole32(d->u.dir[0]); + d->u.dir[1] = lfs1_tole32(d->u.dir[1]); +} + +static void lfs1_superblock_fromle32(struct lfs1_disk_superblock *d) { + d->root[0] = lfs1_fromle32(d->root[0]); + d->root[1] = lfs1_fromle32(d->root[1]); + d->block_size = lfs1_fromle32(d->block_size); + d->block_count = lfs1_fromle32(d->block_count); + d->version = lfs1_fromle32(d->version); +} + +static void lfs1_superblock_tole32(struct lfs1_disk_superblock *d) { + d->root[0] = lfs1_tole32(d->root[0]); + d->root[1] = lfs1_tole32(d->root[1]); + d->block_size = lfs1_tole32(d->block_size); + d->block_count = lfs1_tole32(d->block_count); + d->version = lfs1_tole32(d->version); +} + + +/// Metadata pair and directory operations /// +static inline void lfs1_pairswap(lfs1_block_t pair[2]) { + lfs1_block_t t = pair[0]; + pair[0] = pair[1]; + pair[1] = t; +} + +static inline bool lfs1_pairisnull(const lfs1_block_t pair[2]) { + return pair[0] == 0xffffffff || pair[1] == 0xffffffff; +} + +static inline int lfs1_paircmp( + const lfs1_block_t paira[2], + const lfs1_block_t pairb[2]) { + return !(paira[0] == pairb[0] || paira[1] == pairb[1] || + paira[0] == pairb[1] || paira[1] == pairb[0]); +} + +static inline bool lfs1_pairsync( + const lfs1_block_t paira[2], + const lfs1_block_t pairb[2]) { + return (paira[0] == pairb[0] && paira[1] == pairb[1]) || + (paira[0] == pairb[1] && paira[1] == pairb[0]); +} + +static inline lfs1_size_t lfs1_entry_size(const lfs1_entry_t *entry) { + return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; +} + +static int lfs1_dir_alloc(lfs1_t *lfs1, lfs1_dir_t *dir) { + // allocate pair of dir blocks + for (int i = 0; i < 2; i++) { + int err = lfs1_alloc(lfs1, &dir->pair[i]); + if (err) { + return err; + } + } + + // rather than clobbering one of the blocks we just pretend + // the revision may be valid + int err = lfs1_bd_read(lfs1, dir->pair[0], 0, &dir->d.rev, 4); + if (err && err != LFS1_ERR_CORRUPT) { + return err; + } + + if (err != LFS1_ERR_CORRUPT) { + dir->d.rev = lfs1_fromle32(dir->d.rev); + } + + // set defaults + dir->d.rev += 1; + dir->d.size = sizeof(dir->d)+4; + dir->d.tail[0] = 0xffffffff; + dir->d.tail[1] = 0xffffffff; + dir->off = sizeof(dir->d); + + // don't write out yet, let caller take care of that + return 0; +} + +static int lfs1_dir_fetch(lfs1_t *lfs1, + lfs1_dir_t *dir, const lfs1_block_t pair[2]) { + // copy out pair, otherwise may be aliasing dir + const lfs1_block_t tpair[2] = {pair[0], pair[1]}; + bool valid = false; + + // check both blocks for the most recent revision + for (int i = 0; i < 2; i++) { + struct lfs1_disk_dir test; + int err = lfs1_bd_read(lfs1, tpair[i], 0, &test, sizeof(test)); + lfs1_dir_fromle32(&test); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + continue; + } + return err; + } + + if (valid && lfs1_scmp(test.rev, dir->d.rev) < 0) { + continue; + } + + if ((0x7fffffff & test.size) < sizeof(test)+4 || + (0x7fffffff & test.size) > lfs1->cfg->block_size) { + continue; + } + + uint32_t crc = 0xffffffff; + lfs1_dir_tole32(&test); + lfs1_crc(&crc, &test, sizeof(test)); + lfs1_dir_fromle32(&test); + err = lfs1_bd_crc(lfs1, tpair[i], sizeof(test), + (0x7fffffff & test.size) - sizeof(test), &crc); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + continue; + } + return err; + } + + if (crc != 0) { + continue; + } + + valid = true; + + // setup dir in case it's valid + dir->pair[0] = tpair[(i+0) % 2]; + dir->pair[1] = tpair[(i+1) % 2]; + dir->off = sizeof(dir->d); + dir->d = test; + } + + if (!valid) { + LFS1_ERROR("Corrupted dir pair at %" PRIu32 " %" PRIu32 , + tpair[0], tpair[1]); + return LFS1_ERR_CORRUPT; + } + + return 0; +} + +struct lfs1_region { + lfs1_off_t oldoff; + lfs1_size_t oldlen; + const void *newdata; + lfs1_size_t newlen; +}; + +static int lfs1_dir_commit(lfs1_t *lfs1, lfs1_dir_t *dir, + const struct lfs1_region *regions, int count) { + // increment revision count + dir->d.rev += 1; + + // keep pairs in order such that pair[0] is most recent + lfs1_pairswap(dir->pair); + for (int i = 0; i < count; i++) { + dir->d.size += regions[i].newlen - regions[i].oldlen; + } + + const lfs1_block_t oldpair[2] = {dir->pair[0], dir->pair[1]}; + bool relocated = false; + + while (true) { + if (true) { + int err = lfs1_bd_erase(lfs1, dir->pair[0]); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + uint32_t crc = 0xffffffff; + lfs1_dir_tole32(&dir->d); + lfs1_crc(&crc, &dir->d, sizeof(dir->d)); + err = lfs1_bd_prog(lfs1, dir->pair[0], 0, &dir->d, sizeof(dir->d)); + lfs1_dir_fromle32(&dir->d); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + int i = 0; + lfs1_off_t oldoff = sizeof(dir->d); + lfs1_off_t newoff = sizeof(dir->d); + while (newoff < (0x7fffffff & dir->d.size)-4) { + if (i < count && regions[i].oldoff == oldoff) { + lfs1_crc(&crc, regions[i].newdata, regions[i].newlen); + err = lfs1_bd_prog(lfs1, dir->pair[0], + newoff, regions[i].newdata, regions[i].newlen); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + oldoff += regions[i].oldlen; + newoff += regions[i].newlen; + i += 1; + } else { + uint8_t data; + err = lfs1_bd_read(lfs1, oldpair[1], oldoff, &data, 1); + if (err) { + return err; + } + + lfs1_crc(&crc, &data, 1); + err = lfs1_bd_prog(lfs1, dir->pair[0], newoff, &data, 1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + oldoff += 1; + newoff += 1; + } + } + + crc = lfs1_tole32(crc); + err = lfs1_bd_prog(lfs1, dir->pair[0], newoff, &crc, 4); + crc = lfs1_fromle32(crc); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + err = lfs1_bd_sync(lfs1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // successful commit, check checksum to make sure + uint32_t ncrc = 0xffffffff; + err = lfs1_bd_crc(lfs1, dir->pair[0], 0, + (0x7fffffff & dir->d.size)-4, &ncrc); + if (err) { + return err; + } + + if (ncrc != crc) { + goto relocate; + } + } + + break; +relocate: + //commit was corrupted + LFS1_DEBUG("Bad block at %" PRIu32, dir->pair[0]); + + // drop caches and prepare to relocate block + relocated = true; + lfs1_cache_drop(lfs1, &lfs1->pcache); + + // can't relocate superblock, filesystem is now frozen + if (lfs1_paircmp(oldpair, (const lfs1_block_t[2]){0, 1}) == 0) { + LFS1_WARN("Superblock %" PRIu32 " has become unwritable", + oldpair[0]); + return LFS1_ERR_CORRUPT; + } + + // relocate half of pair + int err = lfs1_alloc(lfs1, &dir->pair[0]); + if (err) { + return err; + } + } + + if (relocated) { + // update references if we relocated + LFS1_DEBUG("Relocating %" PRIu32 " %" PRIu32 " to %" PRIu32 " %" PRIu32, + oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); + int err = lfs1_relocate(lfs1, oldpair, dir->pair); + if (err) { + return err; + } + } + + // shift over any directories that are affected + for (lfs1_dir_t *d = lfs1->dirs; d; d = d->next) { + if (lfs1_paircmp(d->pair, dir->pair) == 0) { + d->pair[0] = dir->pair[0]; + d->pair[1] = dir->pair[1]; + } + } + + return 0; +} + +static int lfs1_dir_update(lfs1_t *lfs1, lfs1_dir_t *dir, + lfs1_entry_t *entry, const void *data) { + lfs1_entry_tole32(&entry->d); + int err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)}, + {entry->off+sizeof(entry->d), entry->d.nlen, data, entry->d.nlen} + }, data ? 2 : 1); + lfs1_entry_fromle32(&entry->d); + return err; +} + +static int lfs1_dir_append(lfs1_t *lfs1, lfs1_dir_t *dir, + lfs1_entry_t *entry, const void *data) { + // check if we fit, if top bit is set we do not and move on + while (true) { + if (dir->d.size + lfs1_entry_size(entry) <= lfs1->cfg->block_size) { + entry->off = dir->d.size - 4; + + lfs1_entry_tole32(&entry->d); + int err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, 0, &entry->d, sizeof(entry->d)}, + {entry->off, 0, data, entry->d.nlen} + }, 2); + lfs1_entry_fromle32(&entry->d); + return err; + } + + // we need to allocate a new dir block + if (!(0x80000000 & dir->d.size)) { + lfs1_dir_t olddir = *dir; + int err = lfs1_dir_alloc(lfs1, dir); + if (err) { + return err; + } + + dir->d.tail[0] = olddir.d.tail[0]; + dir->d.tail[1] = olddir.d.tail[1]; + entry->off = dir->d.size - 4; + lfs1_entry_tole32(&entry->d); + err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, 0, &entry->d, sizeof(entry->d)}, + {entry->off, 0, data, entry->d.nlen} + }, 2); + lfs1_entry_fromle32(&entry->d); + if (err) { + return err; + } + + olddir.d.size |= 0x80000000; + olddir.d.tail[0] = dir->pair[0]; + olddir.d.tail[1] = dir->pair[1]; + return lfs1_dir_commit(lfs1, &olddir, NULL, 0); + } + + int err = lfs1_dir_fetch(lfs1, dir, dir->d.tail); + if (err) { + return err; + } + } +} + +static int lfs1_dir_remove(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_entry_t *entry) { + // check if we should just drop the directory block + if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 + + lfs1_entry_size(entry)) { + lfs1_dir_t pdir; + int res = lfs1_pred(lfs1, dir->pair, &pdir); + if (res < 0) { + return res; + } + + if (pdir.d.size & 0x80000000) { + pdir.d.size &= dir->d.size | 0x7fffffff; + pdir.d.tail[0] = dir->d.tail[0]; + pdir.d.tail[1] = dir->d.tail[1]; + return lfs1_dir_commit(lfs1, &pdir, NULL, 0); + } + } + + // shift out the entry + int err = lfs1_dir_commit(lfs1, dir, (struct lfs1_region[]){ + {entry->off, lfs1_entry_size(entry), NULL, 0}, + }, 1); + if (err) { + return err; + } + + // shift over any files/directories that are affected + for (lfs1_file_t *f = lfs1->files; f; f = f->next) { + if (lfs1_paircmp(f->pair, dir->pair) == 0) { + if (f->poff == entry->off) { + f->pair[0] = 0xffffffff; + f->pair[1] = 0xffffffff; + } else if (f->poff > entry->off) { + f->poff -= lfs1_entry_size(entry); + } + } + } + + for (lfs1_dir_t *d = lfs1->dirs; d; d = d->next) { + if (lfs1_paircmp(d->pair, dir->pair) == 0) { + if (d->off > entry->off) { + d->off -= lfs1_entry_size(entry); + d->pos -= lfs1_entry_size(entry); + } + } + } + + return 0; +} + +static int lfs1_dir_next(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_entry_t *entry) { + while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { + if (!(0x80000000 & dir->d.size)) { + entry->off = dir->off; + return LFS1_ERR_NOENT; + } + + int err = lfs1_dir_fetch(lfs1, dir, dir->d.tail); + if (err) { + return err; + } + + dir->off = sizeof(dir->d); + dir->pos += sizeof(dir->d) + 4; + } + + int err = lfs1_bd_read(lfs1, dir->pair[0], dir->off, + &entry->d, sizeof(entry->d)); + lfs1_entry_fromle32(&entry->d); + if (err) { + return err; + } + + entry->off = dir->off; + dir->off += lfs1_entry_size(entry); + dir->pos += lfs1_entry_size(entry); + return 0; +} + +static int lfs1_dir_find(lfs1_t *lfs1, lfs1_dir_t *dir, + lfs1_entry_t *entry, const char **path) { + const char *pathname = *path; + size_t pathlen; + entry->d.type = LFS1_TYPE_DIR; + entry->d.elen = sizeof(entry->d) - 4; + entry->d.alen = 0; + entry->d.nlen = 0; + entry->d.u.dir[0] = lfs1->root[0]; + entry->d.u.dir[1] = lfs1->root[1]; + + while (true) { +nextname: + // skip slashes + pathname += strspn(pathname, "/"); + pathlen = strcspn(pathname, "/"); + + // skip '.' and root '..' + if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) || + (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) { + pathname += pathlen; + goto nextname; + } + + // skip if matched by '..' in name + const char *suffix = pathname + pathlen; + size_t sufflen; + int depth = 1; + while (true) { + suffix += strspn(suffix, "/"); + sufflen = strcspn(suffix, "/"); + if (sufflen == 0) { + break; + } + + if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + depth -= 1; + if (depth == 0) { + pathname = suffix + sufflen; + goto nextname; + } + } else { + depth += 1; + } + + suffix += sufflen; + } + + // found path + if (pathname[0] == '\0') { + return 0; + } + + // update what we've found + *path = pathname; + + // continue on if we hit a directory + if (entry->d.type != LFS1_TYPE_DIR) { + return LFS1_ERR_NOTDIR; + } + + int err = lfs1_dir_fetch(lfs1, dir, entry->d.u.dir); + if (err) { + return err; + } + + // find entry matching name + while (true) { + err = lfs1_dir_next(lfs1, dir, entry); + if (err) { + return err; + } + + if (((0x7f & entry->d.type) != LFS1_TYPE_REG && + (0x7f & entry->d.type) != LFS1_TYPE_DIR) || + entry->d.nlen != pathlen) { + continue; + } + + int res = lfs1_bd_cmp(lfs1, dir->pair[0], + entry->off + 4+entry->d.elen+entry->d.alen, + pathname, pathlen); + if (res < 0) { + return res; + } + + // found match + if (res) { + break; + } + } + + // check that entry has not been moved + if (!lfs1->moving && entry->d.type & 0x80) { + int moved = lfs1_moved(lfs1, &entry->d.u); + if (moved < 0 || moved) { + return (moved < 0) ? moved : LFS1_ERR_NOENT; + } + + entry->d.type &= ~0x80; + } + + // to next name + pathname += pathlen; + } +} + + +/// Top level directory operations /// +int lfs1_mkdir(lfs1_t *lfs1, const char *path) { + // deorphan if we haven't yet, needed at most once after poweron + if (!lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + // fetch parent directory + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err != LFS1_ERR_NOENT || strchr(path, '/') != NULL) { + return err ? err : LFS1_ERR_EXIST; + } + + // build up new directory + lfs1_alloc_ack(lfs1); + + lfs1_dir_t dir; + err = lfs1_dir_alloc(lfs1, &dir); + if (err) { + return err; + } + dir.d.tail[0] = cwd.d.tail[0]; + dir.d.tail[1] = cwd.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &dir, NULL, 0); + if (err) { + return err; + } + + entry.d.type = LFS1_TYPE_DIR; + entry.d.elen = sizeof(entry.d) - 4; + entry.d.alen = 0; + entry.d.nlen = strlen(path); + entry.d.u.dir[0] = dir.pair[0]; + entry.d.u.dir[1] = dir.pair[1]; + + cwd.d.tail[0] = dir.pair[0]; + cwd.d.tail[1] = dir.pair[1]; + + err = lfs1_dir_append(lfs1, &cwd, &entry, path); + if (err) { + return err; + } + + lfs1_alloc_ack(lfs1); + return 0; +} + +int lfs1_dir_open(lfs1_t *lfs1, lfs1_dir_t *dir, const char *path) { + dir->pair[0] = lfs1->root[0]; + dir->pair[1] = lfs1->root[1]; + + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, dir, &entry, &path); + if (err) { + return err; + } else if (entry.d.type != LFS1_TYPE_DIR) { + return LFS1_ERR_NOTDIR; + } + + err = lfs1_dir_fetch(lfs1, dir, entry.d.u.dir); + if (err) { + return err; + } + + // setup head dir + // special offset for '.' and '..' + dir->head[0] = dir->pair[0]; + dir->head[1] = dir->pair[1]; + dir->pos = sizeof(dir->d) - 2; + dir->off = sizeof(dir->d); + + // add to list of directories + dir->next = lfs1->dirs; + lfs1->dirs = dir; + + return 0; +} + +int lfs1_dir_close(lfs1_t *lfs1, lfs1_dir_t *dir) { + // remove from list of directories + for (lfs1_dir_t **p = &lfs1->dirs; *p; p = &(*p)->next) { + if (*p == dir) { + *p = dir->next; + break; + } + } + + return 0; +} + +int lfs1_dir_read(lfs1_t *lfs1, lfs1_dir_t *dir, struct lfs1_info *info) { + memset(info, 0, sizeof(*info)); + + // special offset for '.' and '..' + if (dir->pos == sizeof(dir->d) - 2) { + info->type = LFS1_TYPE_DIR; + strcpy(info->name, "."); + dir->pos += 1; + return 1; + } else if (dir->pos == sizeof(dir->d) - 1) { + info->type = LFS1_TYPE_DIR; + strcpy(info->name, ".."); + dir->pos += 1; + return 1; + } + + lfs1_entry_t entry; + while (true) { + int err = lfs1_dir_next(lfs1, dir, &entry); + if (err) { + return (err == LFS1_ERR_NOENT) ? 0 : err; + } + + if ((0x7f & entry.d.type) != LFS1_TYPE_REG && + (0x7f & entry.d.type) != LFS1_TYPE_DIR) { + continue; + } + + // check that entry has not been moved + if (entry.d.type & 0x80) { + int moved = lfs1_moved(lfs1, &entry.d.u); + if (moved < 0) { + return moved; + } + + if (moved) { + continue; + } + + entry.d.type &= ~0x80; + } + + break; + } + + info->type = entry.d.type; + if (info->type == LFS1_TYPE_REG) { + info->size = entry.d.u.file.size; + } + + int err = lfs1_bd_read(lfs1, dir->pair[0], + entry.off + 4+entry.d.elen+entry.d.alen, + info->name, entry.d.nlen); + if (err) { + return err; + } + + return 1; +} + +int lfs1_dir_seek(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_off_t off) { + // simply walk from head dir + int err = lfs1_dir_rewind(lfs1, dir); + if (err) { + return err; + } + dir->pos = off; + + while (off > (0x7fffffff & dir->d.size)) { + off -= 0x7fffffff & dir->d.size; + if (!(0x80000000 & dir->d.size)) { + return LFS1_ERR_INVAL; + } + + err = lfs1_dir_fetch(lfs1, dir, dir->d.tail); + if (err) { + return err; + } + } + + dir->off = off; + return 0; +} + +lfs1_soff_t lfs1_dir_tell(lfs1_t *lfs1, lfs1_dir_t *dir) { + (void)lfs1; + return dir->pos; +} + +int lfs1_dir_rewind(lfs1_t *lfs1, lfs1_dir_t *dir) { + // reload the head dir + int err = lfs1_dir_fetch(lfs1, dir, dir->head); + if (err) { + return err; + } + + dir->pair[0] = dir->head[0]; + dir->pair[1] = dir->head[1]; + dir->pos = sizeof(dir->d) - 2; + dir->off = sizeof(dir->d); + return 0; +} + + +/// File index list operations /// +static int lfs1_ctz_index(lfs1_t *lfs1, lfs1_off_t *off) { + lfs1_off_t size = *off; + lfs1_off_t b = lfs1->cfg->block_size - 2*4; + lfs1_off_t i = size / b; + if (i == 0) { + return 0; + } + + i = (size - 4*(lfs1_popc(i-1)+2)) / b; + *off = size - b*i - 4*lfs1_popc(i); + return i; +} + +static int lfs1_ctz_find(lfs1_t *lfs1, + lfs1_cache_t *rcache, const lfs1_cache_t *pcache, + lfs1_block_t head, lfs1_size_t size, + lfs1_size_t pos, lfs1_block_t *block, lfs1_off_t *off) { + if (size == 0) { + *block = 0xffffffff; + *off = 0; + return 0; + } + + lfs1_off_t current = lfs1_ctz_index(lfs1, &(lfs1_off_t){size-1}); + lfs1_off_t target = lfs1_ctz_index(lfs1, &pos); + + while (current > target) { + lfs1_size_t skip = lfs1_min( + lfs1_npw2(current-target+1) - 1, + lfs1_ctz(current)); + + int err = lfs1_cache_read(lfs1, rcache, pcache, head, 4*skip, &head, 4); + head = lfs1_fromle32(head); + if (err) { + return err; + } + + LFS1_ASSERT(head >= 2 && head <= lfs1->cfg->block_count); + current -= 1 << skip; + } + + *block = head; + *off = pos; + return 0; +} + +static int lfs1_ctz_extend(lfs1_t *lfs1, + lfs1_cache_t *rcache, lfs1_cache_t *pcache, + lfs1_block_t head, lfs1_size_t size, + lfs1_block_t *block, lfs1_off_t *off) { + while (true) { + // go ahead and grab a block + lfs1_block_t nblock; + int err = lfs1_alloc(lfs1, &nblock); + if (err) { + return err; + } + LFS1_ASSERT(nblock >= 2 && nblock <= lfs1->cfg->block_count); + + if (true) { + err = lfs1_bd_erase(lfs1, nblock); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (size == 0) { + *block = nblock; + *off = 0; + return 0; + } + + size -= 1; + lfs1_off_t index = lfs1_ctz_index(lfs1, &size); + size += 1; + + // just copy out the last block if it is incomplete + if (size != lfs1->cfg->block_size) { + for (lfs1_off_t i = 0; i < size; i++) { + uint8_t data; + err = lfs1_cache_read(lfs1, rcache, NULL, + head, i, &data, 1); + if (err) { + return err; + } + + err = lfs1_cache_prog(lfs1, pcache, rcache, + nblock, i, &data, 1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + *block = nblock; + *off = size; + return 0; + } + + // append block + index += 1; + lfs1_size_t skips = lfs1_ctz(index) + 1; + + for (lfs1_off_t i = 0; i < skips; i++) { + head = lfs1_tole32(head); + err = lfs1_cache_prog(lfs1, pcache, rcache, + nblock, 4*i, &head, 4); + head = lfs1_fromle32(head); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (i != skips-1) { + err = lfs1_cache_read(lfs1, rcache, NULL, + head, 4*i, &head, 4); + head = lfs1_fromle32(head); + if (err) { + return err; + } + } + + LFS1_ASSERT(head >= 2 && head <= lfs1->cfg->block_count); + } + + *block = nblock; + *off = 4*skips; + return 0; + } + +relocate: + LFS1_DEBUG("Bad block at %" PRIu32, nblock); + + // just clear cache and try a new block + lfs1_cache_drop(lfs1, &lfs1->pcache); + } +} + +static int lfs1_ctz_traverse(lfs1_t *lfs1, + lfs1_cache_t *rcache, const lfs1_cache_t *pcache, + lfs1_block_t head, lfs1_size_t size, + int (*cb)(void*, lfs1_block_t), void *data) { + if (size == 0) { + return 0; + } + + lfs1_off_t index = lfs1_ctz_index(lfs1, &(lfs1_off_t){size-1}); + + while (true) { + int err = cb(data, head); + if (err) { + return err; + } + + if (index == 0) { + return 0; + } + + lfs1_block_t heads[2]; + int count = 2 - (index & 1); + err = lfs1_cache_read(lfs1, rcache, pcache, head, 0, &heads, count*4); + heads[0] = lfs1_fromle32(heads[0]); + heads[1] = lfs1_fromle32(heads[1]); + if (err) { + return err; + } + + for (int i = 0; i < count-1; i++) { + err = cb(data, heads[i]); + if (err) { + return err; + } + } + + head = heads[count-1]; + index -= count; + } +} + + +/// Top level file operations /// +int lfs1_file_opencfg(lfs1_t *lfs1, lfs1_file_t *file, + const char *path, int flags, + const struct lfs1_file_config *cfg) { + // deorphan if we haven't yet, needed at most once after poweron + if ((flags & 3) != LFS1_O_RDONLY && !lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + // allocate entry for file if it doesn't exist + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err && (err != LFS1_ERR_NOENT || strchr(path, '/') != NULL)) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + if (!(flags & LFS1_O_CREAT)) { + return LFS1_ERR_NOENT; + } + + // create entry to remember name + entry.d.type = LFS1_TYPE_REG; + entry.d.elen = sizeof(entry.d) - 4; + entry.d.alen = 0; + entry.d.nlen = strlen(path); + entry.d.u.file.head = 0xffffffff; + entry.d.u.file.size = 0; + err = lfs1_dir_append(lfs1, &cwd, &entry, path); + if (err) { + return err; + } + } else if (entry.d.type == LFS1_TYPE_DIR) { + return LFS1_ERR_ISDIR; + } else if (flags & LFS1_O_EXCL) { + return LFS1_ERR_EXIST; + } + + // setup file struct + file->cfg = cfg; + file->pair[0] = cwd.pair[0]; + file->pair[1] = cwd.pair[1]; + file->poff = entry.off; + file->head = entry.d.u.file.head; + file->size = entry.d.u.file.size; + file->flags = flags; + file->pos = 0; + + if (flags & LFS1_O_TRUNC) { + if (file->size != 0) { + file->flags |= LFS1_F_DIRTY; + } + file->head = 0xffffffff; + file->size = 0; + } + + // allocate buffer if needed + file->cache.block = 0xffffffff; + if (file->cfg && file->cfg->buffer) { + file->cache.buffer = file->cfg->buffer; + } else if (lfs1->cfg->file_buffer) { + if (lfs1->files) { + // already in use + return LFS1_ERR_NOMEM; + } + file->cache.buffer = lfs1->cfg->file_buffer; + } else if ((file->flags & 3) == LFS1_O_RDONLY) { + file->cache.buffer = lfs1_malloc(lfs1->cfg->read_size); + if (!file->cache.buffer) { + return LFS1_ERR_NOMEM; + } + } else { + file->cache.buffer = lfs1_malloc(lfs1->cfg->prog_size); + if (!file->cache.buffer) { + return LFS1_ERR_NOMEM; + } + } + + // zero to avoid information leak + lfs1_cache_drop(lfs1, &file->cache); + if ((file->flags & 3) != LFS1_O_RDONLY) { + lfs1_cache_zero(lfs1, &file->cache); + } + + // add to list of files + file->next = lfs1->files; + lfs1->files = file; + + return 0; +} + +int lfs1_file_open(lfs1_t *lfs1, lfs1_file_t *file, + const char *path, int flags) { + return lfs1_file_opencfg(lfs1, file, path, flags, NULL); +} + +int lfs1_file_close(lfs1_t *lfs1, lfs1_file_t *file) { + int err = lfs1_file_sync(lfs1, file); + + // remove from list of files + for (lfs1_file_t **p = &lfs1->files; *p; p = &(*p)->next) { + if (*p == file) { + *p = file->next; + break; + } + } + + // clean up memory + if (!(file->cfg && file->cfg->buffer) && !lfs1->cfg->file_buffer) { + lfs1_free(file->cache.buffer); + } + + return err; +} + +static int lfs1_file_relocate(lfs1_t *lfs1, lfs1_file_t *file) { +relocate: + LFS1_DEBUG("Bad block at %" PRIu32, file->block); + + // just relocate what exists into new block + lfs1_block_t nblock; + int err = lfs1_alloc(lfs1, &nblock); + if (err) { + return err; + } + + err = lfs1_bd_erase(lfs1, nblock); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // either read from dirty cache or disk + for (lfs1_off_t i = 0; i < file->off; i++) { + uint8_t data; + err = lfs1_cache_read(lfs1, &lfs1->rcache, &file->cache, + file->block, i, &data, 1); + if (err) { + return err; + } + + err = lfs1_cache_prog(lfs1, &lfs1->pcache, &lfs1->rcache, + nblock, i, &data, 1); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // copy over new state of file + memcpy(file->cache.buffer, lfs1->pcache.buffer, lfs1->cfg->prog_size); + file->cache.block = lfs1->pcache.block; + file->cache.off = lfs1->pcache.off; + lfs1_cache_zero(lfs1, &lfs1->pcache); + + file->block = nblock; + return 0; +} + +static int lfs1_file_flush(lfs1_t *lfs1, lfs1_file_t *file) { + if (file->flags & LFS1_F_READING) { + // just drop read cache + lfs1_cache_drop(lfs1, &file->cache); + file->flags &= ~LFS1_F_READING; + } + + if (file->flags & LFS1_F_WRITING) { + lfs1_off_t pos = file->pos; + + // copy over anything after current branch + lfs1_file_t orig = { + .head = file->head, + .size = file->size, + .flags = LFS1_O_RDONLY, + .pos = file->pos, + .cache = lfs1->rcache, + }; + lfs1_cache_drop(lfs1, &lfs1->rcache); + + while (file->pos < file->size) { + // copy over a byte at a time, leave it up to caching + // to make this efficient + uint8_t data; + lfs1_ssize_t res = lfs1_file_read(lfs1, &orig, &data, 1); + if (res < 0) { + return res; + } + + res = lfs1_file_write(lfs1, file, &data, 1); + if (res < 0) { + return res; + } + + // keep our reference to the rcache in sync + if (lfs1->rcache.block != 0xffffffff) { + lfs1_cache_drop(lfs1, &orig.cache); + lfs1_cache_drop(lfs1, &lfs1->rcache); + } + } + + // write out what we have + while (true) { + int err = lfs1_cache_flush(lfs1, &file->cache, &lfs1->rcache); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + break; +relocate: + err = lfs1_file_relocate(lfs1, file); + if (err) { + return err; + } + } + + // actual file updates + file->head = file->block; + file->size = file->pos; + file->flags &= ~LFS1_F_WRITING; + file->flags |= LFS1_F_DIRTY; + + file->pos = pos; + } + + return 0; +} + +int lfs1_file_sync(lfs1_t *lfs1, lfs1_file_t *file) { + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + + if ((file->flags & LFS1_F_DIRTY) && + !(file->flags & LFS1_F_ERRED) && + !lfs1_pairisnull(file->pair)) { + // update dir entry + lfs1_dir_t cwd; + err = lfs1_dir_fetch(lfs1, &cwd, file->pair); + if (err) { + return err; + } + + lfs1_entry_t entry = {.off = file->poff}; + err = lfs1_bd_read(lfs1, cwd.pair[0], entry.off, + &entry.d, sizeof(entry.d)); + lfs1_entry_fromle32(&entry.d); + if (err) { + return err; + } + + LFS1_ASSERT(entry.d.type == LFS1_TYPE_REG); + entry.d.u.file.head = file->head; + entry.d.u.file.size = file->size; + + err = lfs1_dir_update(lfs1, &cwd, &entry, NULL); + if (err) { + return err; + } + + file->flags &= ~LFS1_F_DIRTY; + } + + return 0; +} + +lfs1_ssize_t lfs1_file_read(lfs1_t *lfs1, lfs1_file_t *file, + void *buffer, lfs1_size_t size) { + uint8_t *data = buffer; + lfs1_size_t nsize = size; + + if ((file->flags & 3) == LFS1_O_WRONLY) { + return LFS1_ERR_BADF; + } + + if (file->flags & LFS1_F_WRITING) { + // flush out any writes + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + } + + if (file->pos >= file->size) { + // eof if past end + return 0; + } + + size = lfs1_min(size, file->size - file->pos); + nsize = size; + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS1_F_READING) || + file->off == lfs1->cfg->block_size) { + int err = lfs1_ctz_find(lfs1, &file->cache, NULL, + file->head, file->size, + file->pos, &file->block, &file->off); + if (err) { + return err; + } + + file->flags |= LFS1_F_READING; + } + + // read as much as we can in current block + lfs1_size_t diff = lfs1_min(nsize, lfs1->cfg->block_size - file->off); + int err = lfs1_cache_read(lfs1, &file->cache, NULL, + file->block, file->off, data, diff); + if (err) { + return err; + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + } + + return size; +} + +lfs1_ssize_t lfs1_file_write(lfs1_t *lfs1, lfs1_file_t *file, + const void *buffer, lfs1_size_t size) { + const uint8_t *data = buffer; + lfs1_size_t nsize = size; + + if ((file->flags & 3) == LFS1_O_RDONLY) { + return LFS1_ERR_BADF; + } + + if (file->flags & LFS1_F_READING) { + // drop any reads + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + } + + if ((file->flags & LFS1_O_APPEND) && file->pos < file->size) { + file->pos = file->size; + } + + if (file->pos + size > LFS1_FILE_MAX) { + // larger than file limit? + return LFS1_ERR_FBIG; + } + + if (!(file->flags & LFS1_F_WRITING) && file->pos > file->size) { + // fill with zeros + lfs1_off_t pos = file->pos; + file->pos = file->size; + + while (file->pos < pos) { + lfs1_ssize_t res = lfs1_file_write(lfs1, file, &(uint8_t){0}, 1); + if (res < 0) { + return res; + } + } + } + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS1_F_WRITING) || + file->off == lfs1->cfg->block_size) { + if (!(file->flags & LFS1_F_WRITING) && file->pos > 0) { + // find out which block we're extending from + int err = lfs1_ctz_find(lfs1, &file->cache, NULL, + file->head, file->size, + file->pos-1, &file->block, &file->off); + if (err) { + file->flags |= LFS1_F_ERRED; + return err; + } + + // mark cache as dirty since we may have read data into it + lfs1_cache_zero(lfs1, &file->cache); + } + + // extend file with new blocks + lfs1_alloc_ack(lfs1); + int err = lfs1_ctz_extend(lfs1, &lfs1->rcache, &file->cache, + file->block, file->pos, + &file->block, &file->off); + if (err) { + file->flags |= LFS1_F_ERRED; + return err; + } + + file->flags |= LFS1_F_WRITING; + } + + // program as much as we can in current block + lfs1_size_t diff = lfs1_min(nsize, lfs1->cfg->block_size - file->off); + while (true) { + int err = lfs1_cache_prog(lfs1, &file->cache, &lfs1->rcache, + file->block, file->off, data, diff); + if (err) { + if (err == LFS1_ERR_CORRUPT) { + goto relocate; + } + file->flags |= LFS1_F_ERRED; + return err; + } + + break; +relocate: + err = lfs1_file_relocate(lfs1, file); + if (err) { + file->flags |= LFS1_F_ERRED; + return err; + } + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + + lfs1_alloc_ack(lfs1); + } + + file->flags &= ~LFS1_F_ERRED; + return size; +} + +lfs1_soff_t lfs1_file_seek(lfs1_t *lfs1, lfs1_file_t *file, + lfs1_soff_t off, int whence) { + // write out everything beforehand, may be noop if rdonly + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + + // find new pos + lfs1_soff_t npos = file->pos; + if (whence == LFS1_SEEK_SET) { + npos = off; + } else if (whence == LFS1_SEEK_CUR) { + npos = file->pos + off; + } else if (whence == LFS1_SEEK_END) { + npos = file->size + off; + } + + if (npos < 0 || npos > LFS1_FILE_MAX) { + // file position out of range + return LFS1_ERR_INVAL; + } + + // update pos + file->pos = npos; + return npos; +} + +int lfs1_file_truncate(lfs1_t *lfs1, lfs1_file_t *file, lfs1_off_t size) { + if ((file->flags & 3) == LFS1_O_RDONLY) { + return LFS1_ERR_BADF; + } + + lfs1_off_t oldsize = lfs1_file_size(lfs1, file); + if (size < oldsize) { + // need to flush since directly changing metadata + int err = lfs1_file_flush(lfs1, file); + if (err) { + return err; + } + + // lookup new head in ctz skip list + err = lfs1_ctz_find(lfs1, &file->cache, NULL, + file->head, file->size, + size, &file->head, &(lfs1_off_t){0}); + if (err) { + return err; + } + + file->size = size; + file->flags |= LFS1_F_DIRTY; + } else if (size > oldsize) { + lfs1_off_t pos = file->pos; + + // flush+seek if not already at end + if (file->pos != oldsize) { + int err = lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_END); + if (err < 0) { + return err; + } + } + + // fill with zeros + while (file->pos < size) { + lfs1_ssize_t res = lfs1_file_write(lfs1, file, &(uint8_t){0}, 1); + if (res < 0) { + return res; + } + } + + // restore pos + int err = lfs1_file_seek(lfs1, file, pos, LFS1_SEEK_SET); + if (err < 0) { + return err; + } + } + + return 0; +} + +lfs1_soff_t lfs1_file_tell(lfs1_t *lfs1, lfs1_file_t *file) { + (void)lfs1; + return file->pos; +} + +int lfs1_file_rewind(lfs1_t *lfs1, lfs1_file_t *file) { + lfs1_soff_t res = lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_SET); + if (res < 0) { + return res; + } + + return 0; +} + +lfs1_soff_t lfs1_file_size(lfs1_t *lfs1, lfs1_file_t *file) { + (void)lfs1; + if (file->flags & LFS1_F_WRITING) { + return lfs1_max(file->pos, file->size); + } else { + return file->size; + } +} + + +/// General fs operations /// +int lfs1_stat(lfs1_t *lfs1, const char *path, struct lfs1_info *info) { + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err) { + return err; + } + + memset(info, 0, sizeof(*info)); + info->type = entry.d.type; + if (info->type == LFS1_TYPE_REG) { + info->size = entry.d.u.file.size; + } + + if (lfs1_paircmp(entry.d.u.dir, lfs1->root) == 0) { + strcpy(info->name, "/"); + } else { + err = lfs1_bd_read(lfs1, cwd.pair[0], + entry.off + 4+entry.d.elen+entry.d.alen, + info->name, entry.d.nlen); + if (err) { + return err; + } + } + + return 0; +} + +int lfs1_remove(lfs1_t *lfs1, const char *path) { + // deorphan if we haven't yet, needed at most once after poweron + if (!lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + lfs1_dir_t cwd; + lfs1_entry_t entry; + int err = lfs1_dir_find(lfs1, &cwd, &entry, &path); + if (err) { + return err; + } + + lfs1_dir_t dir; + if (entry.d.type == LFS1_TYPE_DIR) { + // must be empty before removal, checking size + // without masking top bit checks for any case where + // dir is not empty + err = lfs1_dir_fetch(lfs1, &dir, entry.d.u.dir); + if (err) { + return err; + } else if (dir.d.size != sizeof(dir.d)+4) { + return LFS1_ERR_NOTEMPTY; + } + } + + // remove the entry + err = lfs1_dir_remove(lfs1, &cwd, &entry); + if (err) { + return err; + } + + // if we were a directory, find pred, replace tail + if (entry.d.type == LFS1_TYPE_DIR) { + int res = lfs1_pred(lfs1, dir.pair, &cwd); + if (res < 0) { + return res; + } + + LFS1_ASSERT(res); // must have pred + cwd.d.tail[0] = dir.d.tail[0]; + cwd.d.tail[1] = dir.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &cwd, NULL, 0); + if (err) { + return err; + } + } + + return 0; +} + +int lfs1_rename(lfs1_t *lfs1, const char *oldpath, const char *newpath) { + // deorphan if we haven't yet, needed at most once after poweron + if (!lfs1->deorphaned) { + int err = lfs1_deorphan(lfs1); + if (err) { + return err; + } + } + + // find old entry + lfs1_dir_t oldcwd; + lfs1_entry_t oldentry; + int err = lfs1_dir_find(lfs1, &oldcwd, &oldentry, &(const char *){oldpath}); + if (err) { + return err; + } + + // mark as moving + oldentry.d.type |= 0x80; + err = lfs1_dir_update(lfs1, &oldcwd, &oldentry, NULL); + if (err) { + return err; + } + + // allocate new entry + lfs1_dir_t newcwd; + lfs1_entry_t preventry; + err = lfs1_dir_find(lfs1, &newcwd, &preventry, &newpath); + if (err && (err != LFS1_ERR_NOENT || strchr(newpath, '/') != NULL)) { + return err; + } + + // must have same type + bool prevexists = (err != LFS1_ERR_NOENT); + if (prevexists && preventry.d.type != (0x7f & oldentry.d.type)) { + return LFS1_ERR_ISDIR; + } + + lfs1_dir_t dir; + if (prevexists && preventry.d.type == LFS1_TYPE_DIR) { + // must be empty before removal, checking size + // without masking top bit checks for any case where + // dir is not empty + err = lfs1_dir_fetch(lfs1, &dir, preventry.d.u.dir); + if (err) { + return err; + } else if (dir.d.size != sizeof(dir.d)+4) { + return LFS1_ERR_NOTEMPTY; + } + } + + // move to new location + lfs1_entry_t newentry = preventry; + newentry.d = oldentry.d; + newentry.d.type &= ~0x80; + newentry.d.nlen = strlen(newpath); + + if (prevexists) { + err = lfs1_dir_update(lfs1, &newcwd, &newentry, newpath); + if (err) { + return err; + } + } else { + err = lfs1_dir_append(lfs1, &newcwd, &newentry, newpath); + if (err) { + return err; + } + } + + // fetch old pair again in case dir block changed + lfs1->moving = true; + err = lfs1_dir_find(lfs1, &oldcwd, &oldentry, &oldpath); + if (err) { + return err; + } + lfs1->moving = false; + + // remove old entry + err = lfs1_dir_remove(lfs1, &oldcwd, &oldentry); + if (err) { + return err; + } + + // if we were a directory, find pred, replace tail + if (prevexists && preventry.d.type == LFS1_TYPE_DIR) { + int res = lfs1_pred(lfs1, dir.pair, &newcwd); + if (res < 0) { + return res; + } + + LFS1_ASSERT(res); // must have pred + newcwd.d.tail[0] = dir.d.tail[0]; + newcwd.d.tail[1] = dir.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &newcwd, NULL, 0); + if (err) { + return err; + } + } + + return 0; +} + + +/// Filesystem operations /// +static void lfs1_deinit(lfs1_t *lfs1) { + // free allocated memory + if (!lfs1->cfg->read_buffer) { + lfs1_free(lfs1->rcache.buffer); + } + + if (!lfs1->cfg->prog_buffer) { + lfs1_free(lfs1->pcache.buffer); + } + + if (!lfs1->cfg->lookahead_buffer) { + lfs1_free(lfs1->free.buffer); + } +} + +static int lfs1_init(lfs1_t *lfs1, const struct lfs1_config *cfg) { + lfs1->cfg = cfg; + + // setup read cache + if (lfs1->cfg->read_buffer) { + lfs1->rcache.buffer = lfs1->cfg->read_buffer; + } else { + lfs1->rcache.buffer = lfs1_malloc(lfs1->cfg->read_size); + if (!lfs1->rcache.buffer) { + goto cleanup; + } + } + + // setup program cache + if (lfs1->cfg->prog_buffer) { + lfs1->pcache.buffer = lfs1->cfg->prog_buffer; + } else { + lfs1->pcache.buffer = lfs1_malloc(lfs1->cfg->prog_size); + if (!lfs1->pcache.buffer) { + goto cleanup; + } + } + + // zero to avoid information leaks + lfs1_cache_zero(lfs1, &lfs1->pcache); + lfs1_cache_drop(lfs1, &lfs1->rcache); + + // setup lookahead, round down to nearest 32-bits + LFS1_ASSERT(lfs1->cfg->lookahead % 32 == 0); + LFS1_ASSERT(lfs1->cfg->lookahead > 0); + if (lfs1->cfg->lookahead_buffer) { + lfs1->free.buffer = lfs1->cfg->lookahead_buffer; + } else { + lfs1->free.buffer = lfs1_malloc(lfs1->cfg->lookahead/8); + if (!lfs1->free.buffer) { + goto cleanup; + } + } + + // check that program and read sizes are multiples of the block size + LFS1_ASSERT(lfs1->cfg->prog_size % lfs1->cfg->read_size == 0); + LFS1_ASSERT(lfs1->cfg->block_size % lfs1->cfg->prog_size == 0); + + // check that the block size is large enough to fit ctz pointers + LFS1_ASSERT(4*lfs1_npw2(0xffffffff / (lfs1->cfg->block_size-2*4)) + <= lfs1->cfg->block_size); + + // setup default state + lfs1->root[0] = 0xffffffff; + lfs1->root[1] = 0xffffffff; + lfs1->files = NULL; + lfs1->dirs = NULL; + lfs1->deorphaned = false; + lfs1->moving = false; + + return 0; + +cleanup: + lfs1_deinit(lfs1); + return LFS1_ERR_NOMEM; +} + +int lfs1_format(lfs1_t *lfs1, const struct lfs1_config *cfg) { + int err = 0; + if (true) { + err = lfs1_init(lfs1, cfg); + if (err) { + return err; + } + + // create free lookahead + memset(lfs1->free.buffer, 0, lfs1->cfg->lookahead/8); + lfs1->free.off = 0; + lfs1->free.size = lfs1_min(lfs1->cfg->lookahead, lfs1->cfg->block_count); + lfs1->free.i = 0; + lfs1_alloc_ack(lfs1); + + // create superblock dir + lfs1_dir_t superdir; + err = lfs1_dir_alloc(lfs1, &superdir); + if (err) { + goto cleanup; + } + + // write root directory + lfs1_dir_t root; + err = lfs1_dir_alloc(lfs1, &root); + if (err) { + goto cleanup; + } + + err = lfs1_dir_commit(lfs1, &root, NULL, 0); + if (err) { + goto cleanup; + } + + lfs1->root[0] = root.pair[0]; + lfs1->root[1] = root.pair[1]; + + // write superblocks + lfs1_superblock_t superblock = { + .off = sizeof(superdir.d), + .d.type = LFS1_TYPE_SUPERBLOCK, + .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4, + .d.nlen = sizeof(superblock.d.magic), + .d.version = LFS1_DISK_VERSION, + .d.magic = {"littlefs"}, + .d.block_size = lfs1->cfg->block_size, + .d.block_count = lfs1->cfg->block_count, + .d.root = {lfs1->root[0], lfs1->root[1]}, + }; + superdir.d.tail[0] = root.pair[0]; + superdir.d.tail[1] = root.pair[1]; + superdir.d.size = sizeof(superdir.d) + sizeof(superblock.d) + 4; + + // write both pairs to be safe + lfs1_superblock_tole32(&superblock.d); + bool valid = false; + for (int i = 0; i < 2; i++) { + err = lfs1_dir_commit(lfs1, &superdir, (struct lfs1_region[]){ + {sizeof(superdir.d), sizeof(superblock.d), + &superblock.d, sizeof(superblock.d)} + }, 1); + if (err && err != LFS1_ERR_CORRUPT) { + goto cleanup; + } + + valid = valid || !err; + } + + if (!valid) { + err = LFS1_ERR_CORRUPT; + goto cleanup; + } + + // sanity check that fetch works + err = lfs1_dir_fetch(lfs1, &superdir, (const lfs1_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + lfs1_alloc_ack(lfs1); + } + +cleanup: + lfs1_deinit(lfs1); + return err; +} + +int lfs1_mount(lfs1_t *lfs1, const struct lfs1_config *cfg) { + int err = 0; + if (true) { + err = lfs1_init(lfs1, cfg); + if (err) { + return err; + } + + // setup free lookahead + lfs1->free.off = 0; + lfs1->free.size = 0; + lfs1->free.i = 0; + lfs1_alloc_ack(lfs1); + + // load superblock + lfs1_dir_t dir; + lfs1_superblock_t superblock; + err = lfs1_dir_fetch(lfs1, &dir, (const lfs1_block_t[2]){0, 1}); + if (err && err != LFS1_ERR_CORRUPT) { + goto cleanup; + } + + if (!err) { + err = lfs1_bd_read(lfs1, dir.pair[0], sizeof(dir.d), + &superblock.d, sizeof(superblock.d)); + lfs1_superblock_fromle32(&superblock.d); + if (err) { + goto cleanup; + } + + lfs1->root[0] = superblock.d.root[0]; + lfs1->root[1] = superblock.d.root[1]; + } + + if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { + LFS1_ERROR("Invalid superblock at %d %d", 0, 1); + err = LFS1_ERR_CORRUPT; + goto cleanup; + } + + uint16_t major_version = (0xffff & (superblock.d.version >> 16)); + uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); + if ((major_version != LFS1_DISK_VERSION_MAJOR || + minor_version > LFS1_DISK_VERSION_MINOR)) { + LFS1_ERROR("Invalid version %d.%d", major_version, minor_version); + err = LFS1_ERR_INVAL; + goto cleanup; + } + + return 0; + } + +cleanup: + + lfs1_deinit(lfs1); + return err; +} + +int lfs1_unmount(lfs1_t *lfs1) { + lfs1_deinit(lfs1); + return 0; +} + + +/// Littlefs specific operations /// +int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + // iterate over metadata pairs + lfs1_dir_t dir; + lfs1_entry_t entry; + lfs1_block_t cwd[2] = {0, 1}; + + while (true) { + for (int i = 0; i < 2; i++) { + int err = cb(data, cwd[i]); + if (err) { + return err; + } + } + + int err = lfs1_dir_fetch(lfs1, &dir, cwd); + if (err) { + return err; + } + + // iterate over contents + while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { + err = lfs1_bd_read(lfs1, dir.pair[0], dir.off, + &entry.d, sizeof(entry.d)); + lfs1_entry_fromle32(&entry.d); + if (err) { + return err; + } + + dir.off += lfs1_entry_size(&entry); + if ((0x70 & entry.d.type) == (0x70 & LFS1_TYPE_REG)) { + err = lfs1_ctz_traverse(lfs1, &lfs1->rcache, NULL, + entry.d.u.file.head, entry.d.u.file.size, cb, data); + if (err) { + return err; + } + } + } + + cwd[0] = dir.d.tail[0]; + cwd[1] = dir.d.tail[1]; + + if (lfs1_pairisnull(cwd)) { + break; + } + } + + // iterate over any open files + for (lfs1_file_t *f = lfs1->files; f; f = f->next) { + if (f->flags & LFS1_F_DIRTY) { + int err = lfs1_ctz_traverse(lfs1, &lfs1->rcache, &f->cache, + f->head, f->size, cb, data); + if (err) { + return err; + } + } + + if (f->flags & LFS1_F_WRITING) { + int err = lfs1_ctz_traverse(lfs1, &lfs1->rcache, &f->cache, + f->block, f->pos, cb, data); + if (err) { + return err; + } + } + } + + return 0; +} + +static int lfs1_pred(lfs1_t *lfs1, const lfs1_block_t dir[2], lfs1_dir_t *pdir) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + // iterate over all directory directory entries + int err = lfs1_dir_fetch(lfs1, pdir, (const lfs1_block_t[2]){0, 1}); + if (err) { + return err; + } + + while (!lfs1_pairisnull(pdir->d.tail)) { + if (lfs1_paircmp(pdir->d.tail, dir) == 0) { + return true; + } + + err = lfs1_dir_fetch(lfs1, pdir, pdir->d.tail); + if (err) { + return err; + } + } + + return false; +} + +static int lfs1_parent(lfs1_t *lfs1, const lfs1_block_t dir[2], + lfs1_dir_t *parent, lfs1_entry_t *entry) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + parent->d.tail[0] = 0; + parent->d.tail[1] = 1; + + // iterate over all directory directory entries + while (!lfs1_pairisnull(parent->d.tail)) { + int err = lfs1_dir_fetch(lfs1, parent, parent->d.tail); + if (err) { + return err; + } + + while (true) { + err = lfs1_dir_next(lfs1, parent, entry); + if (err && err != LFS1_ERR_NOENT) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + break; + } + + if (((0x70 & entry->d.type) == (0x70 & LFS1_TYPE_DIR)) && + lfs1_paircmp(entry->d.u.dir, dir) == 0) { + return true; + } + } + } + + return false; +} + +static int lfs1_moved(lfs1_t *lfs1, const void *e) { + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + // skip superblock + lfs1_dir_t cwd; + int err = lfs1_dir_fetch(lfs1, &cwd, (const lfs1_block_t[2]){0, 1}); + if (err) { + return err; + } + + // iterate over all directory directory entries + lfs1_entry_t entry; + while (!lfs1_pairisnull(cwd.d.tail)) { + err = lfs1_dir_fetch(lfs1, &cwd, cwd.d.tail); + if (err) { + return err; + } + + while (true) { + err = lfs1_dir_next(lfs1, &cwd, &entry); + if (err && err != LFS1_ERR_NOENT) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + break; + } + + if (!(0x80 & entry.d.type) && + memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { + return true; + } + } + } + + return false; +} + +static int lfs1_relocate(lfs1_t *lfs1, + const lfs1_block_t oldpair[2], const lfs1_block_t newpair[2]) { + // find parent + lfs1_dir_t parent; + lfs1_entry_t entry; + int res = lfs1_parent(lfs1, oldpair, &parent, &entry); + if (res < 0) { + return res; + } + + if (res) { + // update disk, this creates a desync + entry.d.u.dir[0] = newpair[0]; + entry.d.u.dir[1] = newpair[1]; + + int err = lfs1_dir_update(lfs1, &parent, &entry, NULL); + if (err) { + return err; + } + + // update internal root + if (lfs1_paircmp(oldpair, lfs1->root) == 0) { + LFS1_DEBUG("Relocating root %" PRIu32 " %" PRIu32, + newpair[0], newpair[1]); + lfs1->root[0] = newpair[0]; + lfs1->root[1] = newpair[1]; + } + + // clean up bad block, which should now be a desync + return lfs1_deorphan(lfs1); + } + + // find pred + res = lfs1_pred(lfs1, oldpair, &parent); + if (res < 0) { + return res; + } + + if (res) { + // just replace bad pair, no desync can occur + parent.d.tail[0] = newpair[0]; + parent.d.tail[1] = newpair[1]; + + return lfs1_dir_commit(lfs1, &parent, NULL, 0); + } + + // couldn't find dir, must be new + return 0; +} + +int lfs1_deorphan(lfs1_t *lfs1) { + lfs1->deorphaned = true; + + if (lfs1_pairisnull(lfs1->root)) { + return 0; + } + + lfs1_dir_t pdir = {.d.size = 0x80000000}; + lfs1_dir_t cwd = {.d.tail[0] = 0, .d.tail[1] = 1}; + + // iterate over all directory directory entries + for (lfs1_size_t i = 0; i < lfs1->cfg->block_count; i++) { + if (lfs1_pairisnull(cwd.d.tail)) { + return 0; + } + + int err = lfs1_dir_fetch(lfs1, &cwd, cwd.d.tail); + if (err) { + return err; + } + + // check head blocks for orphans + if (!(0x80000000 & pdir.d.size)) { + // check if we have a parent + lfs1_dir_t parent; + lfs1_entry_t entry; + int res = lfs1_parent(lfs1, pdir.d.tail, &parent, &entry); + if (res < 0) { + return res; + } + + if (!res) { + // we are an orphan + LFS1_DEBUG("Found orphan %" PRIu32 " %" PRIu32, + pdir.d.tail[0], pdir.d.tail[1]); + + pdir.d.tail[0] = cwd.d.tail[0]; + pdir.d.tail[1] = cwd.d.tail[1]; + + err = lfs1_dir_commit(lfs1, &pdir, NULL, 0); + if (err) { + return err; + } + + return 0; + } + + if (!lfs1_pairsync(entry.d.u.dir, pdir.d.tail)) { + // we have desynced + LFS1_DEBUG("Found desync %" PRIu32 " %" PRIu32, + entry.d.u.dir[0], entry.d.u.dir[1]); + + pdir.d.tail[0] = entry.d.u.dir[0]; + pdir.d.tail[1] = entry.d.u.dir[1]; + + err = lfs1_dir_commit(lfs1, &pdir, NULL, 0); + if (err) { + return err; + } + + return 0; + } + } + + // check entries for moves + lfs1_entry_t entry; + while (true) { + err = lfs1_dir_next(lfs1, &cwd, &entry); + if (err && err != LFS1_ERR_NOENT) { + return err; + } + + if (err == LFS1_ERR_NOENT) { + break; + } + + // found moved entry + if (entry.d.type & 0x80) { + int moved = lfs1_moved(lfs1, &entry.d.u); + if (moved < 0) { + return moved; + } + + if (moved) { + LFS1_DEBUG("Found move %" PRIu32 " %" PRIu32, + entry.d.u.dir[0], entry.d.u.dir[1]); + err = lfs1_dir_remove(lfs1, &cwd, &entry); + if (err) { + return err; + } + } else { + LFS1_DEBUG("Found partial move %" PRIu32 " %" PRIu32, + entry.d.u.dir[0], entry.d.u.dir[1]); + entry.d.type &= ~0x80; + err = lfs1_dir_update(lfs1, &cwd, &entry, NULL); + if (err) { + return err; + } + } + } + } + + memcpy(&pdir, &cwd, sizeof(pdir)); + } + + // If we reached here, we have more directory pairs than blocks in the + // filesystem... So something must be horribly wrong + return LFS1_ERR_CORRUPT; +} diff --git a/lfs.h b/lfs1.h similarity index 57% rename from lfs.h rename to lfs1.h index 9c3174e..355c145 100644 --- a/lfs.h +++ b/lfs1.h @@ -4,8 +4,8 @@ * Copyright (c) 2017, Arm Limited. All rights reserved. * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef LFS_H -#define LFS_H +#ifndef LFS1_H +#define LFS1_H #include #include @@ -21,142 +21,142 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS_VERSION 0x00010007 -#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) -#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) +#define LFS1_VERSION 0x00010007 +#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16)) +#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0)) // Version of On-disk data structures // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS_DISK_VERSION 0x00010001 -#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) -#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0)) +#define LFS1_DISK_VERSION 0x00010001 +#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16)) +#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0)) /// Definitions /// // Type definitions -typedef uint32_t lfs_size_t; -typedef uint32_t lfs_off_t; +typedef uint32_t lfs1_size_t; +typedef uint32_t lfs1_off_t; -typedef int32_t lfs_ssize_t; -typedef int32_t lfs_soff_t; +typedef int32_t lfs1_ssize_t; +typedef int32_t lfs1_soff_t; -typedef uint32_t lfs_block_t; +typedef uint32_t lfs1_block_t; // Max name size in bytes -#ifndef LFS_NAME_MAX -#define LFS_NAME_MAX 255 +#ifndef LFS1_NAME_MAX +#define LFS1_NAME_MAX 255 #endif // Max file size in bytes -#ifndef LFS_FILE_MAX -#define LFS_FILE_MAX 2147483647 +#ifndef LFS1_FILE_MAX +#define LFS1_FILE_MAX 2147483647 #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 = -52, // 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 +enum lfs1_error { + LFS1_ERR_OK = 0, // No error + LFS1_ERR_IO = -5, // Error during device operation + LFS1_ERR_CORRUPT = -52, // Corrupted + LFS1_ERR_NOENT = -2, // No directory entry + LFS1_ERR_EXIST = -17, // Entry already exists + LFS1_ERR_NOTDIR = -20, // Entry is not a dir + LFS1_ERR_ISDIR = -21, // Entry is a dir + LFS1_ERR_NOTEMPTY = -39, // Dir is not empty + LFS1_ERR_BADF = -9, // Bad file number + LFS1_ERR_FBIG = -27, // File too large + LFS1_ERR_INVAL = -22, // Invalid parameter + LFS1_ERR_NOSPC = -28, // No space left on device + LFS1_ERR_NOMEM = -12, // No more memory available }; // File types -enum lfs_type { - LFS_TYPE_REG = 0x11, - LFS_TYPE_DIR = 0x22, - LFS_TYPE_SUPERBLOCK = 0x2e, +enum lfs1_type { + LFS1_TYPE_REG = 0x11, + LFS1_TYPE_DIR = 0x22, + LFS1_TYPE_SUPERBLOCK = 0x2e, }; // File open flags -enum lfs_open_flags { +enum lfs1_open_flags { // open flags - LFS_O_RDONLY = 1, // Open a file as read only - LFS_O_WRONLY = 2, // Open a file as write only - LFS_O_RDWR = 3, // Open a file as read and write - LFS_O_CREAT = 0x0100, // Create a file if it does not exist - LFS_O_EXCL = 0x0200, // Fail if a file already exists - LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size - LFS_O_APPEND = 0x0800, // Move to end of file on every write + LFS1_O_RDONLY = 1, // Open a file as read only + LFS1_O_WRONLY = 2, // Open a file as write only + LFS1_O_RDWR = 3, // Open a file as read and write + LFS1_O_CREAT = 0x0100, // Create a file if it does not exist + LFS1_O_EXCL = 0x0200, // Fail if a file already exists + LFS1_O_TRUNC = 0x0400, // Truncate the existing file to zero size + LFS1_O_APPEND = 0x0800, // Move to end of file on every write // internally used flags - LFS_F_DIRTY = 0x10000, // File does not match storage - LFS_F_WRITING = 0x20000, // File has been written since last flush - LFS_F_READING = 0x40000, // File has been read since last flush - LFS_F_ERRED = 0x80000, // An error occured during write + LFS1_F_DIRTY = 0x10000, // File does not match storage + LFS1_F_WRITING = 0x20000, // File has been written since last flush + LFS1_F_READING = 0x40000, // File has been read since last flush + LFS1_F_ERRED = 0x80000, // An error occured during write }; // File seek flags -enum 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 lfs1_whence_flags { + LFS1_SEEK_SET = 0, // Seek relative to an absolute position + LFS1_SEEK_CUR = 1, // Seek relative to the current file position + LFS1_SEEK_END = 2, // Seek relative to the end of the file }; // Configuration provided during initialization of the littlefs -struct lfs_config { +struct lfs1_config { // Opaque user provided context that can be used to pass // information to the block device operations void *context; // Read a region in a block. Negative error codes are propogated // to the user. - int (*read)(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size); + int (*read)(const struct lfs1_config *c, lfs1_block_t block, + lfs1_off_t off, void *buffer, lfs1_size_t size); // Program a region in a block. The block must have previously // been erased. Negative error codes are propogated to the user. - // May return 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); + // May return LFS1_ERR_CORRUPT if the block should be considered bad. + int (*prog)(const struct lfs1_config *c, lfs1_block_t block, + lfs1_off_t off, const void *buffer, lfs1_size_t size); // Erase a block. A block must be erased before being programmed. // The state of an erased block is undefined. Negative error codes // are propogated to the user. - // May return LFS_ERR_CORRUPT if the block should be considered bad. - int (*erase)(const struct lfs_config *c, lfs_block_t block); + // May return LFS1_ERR_CORRUPT if the block should be considered bad. + int (*erase)(const struct lfs1_config *c, lfs1_block_t block); // Sync the state of the underlying block device. Negative error codes // are propogated to the user. - int (*sync)(const struct lfs_config *c); + int (*sync)(const struct lfs1_config *c); // Minimum size of a block read. This determines the size of read buffers. // This may be larger than the physical read size to improve performance // by caching more of the block device. - lfs_size_t read_size; + lfs1_size_t read_size; // Minimum size of a block program. This determines the size of program // buffers. This may be larger than the physical program size to improve // performance by caching more of the block device. // Must be a multiple of the read size. - lfs_size_t prog_size; + lfs1_size_t prog_size; // Size of an erasable block. This does not impact ram consumption and // may be larger than the physical erase size. However, this should be // kept small as each file currently takes up an entire block. // Must be a multiple of the program size. - lfs_size_t block_size; + lfs1_size_t block_size; // Number of erasable blocks on the device. - lfs_size_t block_count; + lfs1_size_t block_count; // Number of blocks to lookahead during block allocation. A larger // lookahead reduces the number of passes required to allocate a block. // The lookahead buffer requires only 1 bit per block so it can be quite // large with little ram impact. Should be a multiple of 32. - lfs_size_t lookahead; + lfs1_size_t lookahead; // Optional, statically allocated read buffer. Must be read sized. void *read_buffer; @@ -173,121 +173,121 @@ struct lfs_config { void *file_buffer; }; -// Optional configuration provided during lfs_file_opencfg -struct lfs_file_config { +// Optional configuration provided during lfs1_file_opencfg +struct lfs1_file_config { // Optional, statically allocated buffer for files. Must be program sized. // If NULL, malloc will be used by default. void *buffer; }; // File info structure -struct lfs_info { - // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR +struct lfs1_info { + // Type of the file, either LFS1_TYPE_REG or LFS1_TYPE_DIR uint8_t type; // Size of the file, only valid for REG files - lfs_size_t size; + lfs1_size_t size; // Name of the file stored as a null-terminated string - char name[LFS_NAME_MAX+1]; + char name[LFS1_NAME_MAX+1]; }; /// littlefs data structures /// -typedef struct lfs_entry { - lfs_off_t off; +typedef struct lfs1_entry { + lfs1_off_t off; - struct lfs_disk_entry { + struct lfs1_disk_entry { uint8_t type; uint8_t elen; uint8_t alen; uint8_t nlen; union { struct { - lfs_block_t head; - lfs_size_t size; + lfs1_block_t head; + lfs1_size_t size; } file; - lfs_block_t dir[2]; + lfs1_block_t dir[2]; } u; } d; -} lfs_entry_t; +} lfs1_entry_t; -typedef struct lfs_cache { - lfs_block_t block; - lfs_off_t off; +typedef struct lfs1_cache { + lfs1_block_t block; + lfs1_off_t off; uint8_t *buffer; -} lfs_cache_t; +} lfs1_cache_t; -typedef struct lfs_file { - struct lfs_file *next; - lfs_block_t pair[2]; - lfs_off_t poff; +typedef struct lfs1_file { + struct lfs1_file *next; + lfs1_block_t pair[2]; + lfs1_off_t poff; - lfs_block_t head; - lfs_size_t size; + lfs1_block_t head; + lfs1_size_t size; - const struct lfs_file_config *cfg; + const struct lfs1_file_config *cfg; uint32_t flags; - lfs_off_t pos; - lfs_block_t block; - lfs_off_t off; - lfs_cache_t cache; -} lfs_file_t; + lfs1_off_t pos; + lfs1_block_t block; + lfs1_off_t off; + lfs1_cache_t cache; +} lfs1_file_t; -typedef struct lfs_dir { - struct lfs_dir *next; - lfs_block_t pair[2]; - lfs_off_t off; +typedef struct lfs1_dir { + struct lfs1_dir *next; + lfs1_block_t pair[2]; + lfs1_off_t off; - lfs_block_t head[2]; - lfs_off_t pos; + lfs1_block_t head[2]; + lfs1_off_t pos; - struct lfs_disk_dir { + struct lfs1_disk_dir { uint32_t rev; - lfs_size_t size; - lfs_block_t tail[2]; + lfs1_size_t size; + lfs1_block_t tail[2]; } d; -} lfs_dir_t; +} lfs1_dir_t; -typedef struct lfs_superblock { - lfs_off_t off; +typedef struct lfs1_superblock { + lfs1_off_t off; - struct lfs_disk_superblock { + struct lfs1_disk_superblock { uint8_t type; uint8_t elen; uint8_t alen; uint8_t nlen; - lfs_block_t root[2]; + lfs1_block_t root[2]; uint32_t block_size; uint32_t block_count; uint32_t version; char magic[8]; } d; -} lfs_superblock_t; +} lfs1_superblock_t; -typedef struct lfs_free { - lfs_block_t off; - lfs_block_t size; - lfs_block_t i; - lfs_block_t ack; +typedef struct lfs1_free { + lfs1_block_t off; + lfs1_block_t size; + lfs1_block_t i; + lfs1_block_t ack; uint32_t *buffer; -} lfs_free_t; +} lfs1_free_t; // The littlefs type -typedef struct lfs { - const struct lfs_config *cfg; +typedef struct lfs1 { + const struct lfs1_config *cfg; - lfs_block_t root[2]; - lfs_file_t *files; - lfs_dir_t *dirs; + lfs1_block_t root[2]; + lfs1_file_t *files; + lfs1_dir_t *dirs; - lfs_cache_t rcache; - lfs_cache_t pcache; + lfs1_cache_t rcache; + lfs1_cache_t pcache; - lfs_free_t free; + lfs1_free_t free; bool deorphaned; bool moving; -} lfs_t; +} lfs1_t; /// Filesystem functions /// @@ -299,23 +299,23 @@ 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 lfs1_format(lfs1_t *lfs1, const struct lfs1_config *config); // Mounts a littlefs // // Requires a littlefs object and config struct. Multiple filesystems // may be mounted simultaneously with multiple littlefs objects. Both -// lfs and config must be allocated while mounted. The config struct must +// lfs1 and config must be allocated while mounted. The config struct must // be zeroed for defaults and backwards compatibility. // // Returns a negative error code on failure. -int lfs_mount(lfs_t *lfs, const struct lfs_config *config); +int lfs1_mount(lfs1_t *lfs1, const struct lfs1_config *config); // Unmounts a littlefs // // Does nothing besides releasing any allocated resources. // Returns a negative error code on failure. -int lfs_unmount(lfs_t *lfs); +int lfs1_unmount(lfs1_t *lfs1); /// General operations /// @@ -323,7 +323,7 @@ int lfs_unmount(lfs_t *lfs); // // 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 lfs1_remove(lfs1_t *lfs1, const char *path); // Rename or move a file or directory // @@ -331,13 +331,13 @@ int lfs_remove(lfs_t *lfs, const char *path); // 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 lfs1_rename(lfs1_t *lfs1, const char *oldpath, const char *newpath); // Find info about a file or directory // // Fills out the info structure, based on the specified file or directory. // Returns a negative error code on failure. -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); +int lfs1_stat(lfs1_t *lfs1, const char *path, struct lfs1_info *info); /// File operations /// @@ -345,25 +345,25 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); // 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 lfs1_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 lfs1_file_open(lfs1_t *lfs1, lfs1_file_t *file, const char *path, int flags); // Open a file with extra configuration // // The mode that the file is opened in is determined by the flags, which -// are values from the enum lfs_open_flags that are bitwise-ored together. +// are values from the enum lfs1_open_flags that are bitwise-ored together. // // The config struct provides additional config options per file as described // above. The config struct must be allocated while the file is open, and the // config struct must be zeroed for defaults and backwards compatibility. // // Returns a negative error code on failure. -int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, +int lfs1_file_opencfg(lfs1_t *lfs1, lfs1_file_t *file, const char *path, int flags, - const struct lfs_file_config *config); + const struct lfs1_file_config *config); // Close a file // @@ -371,20 +371,20 @@ 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 lfs1_file_close(lfs1_t *lfs1, lfs1_file_t *file); // Synchronize a file on storage // // Any pending writes are written out to storage. // Returns a negative error code on failure. -int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); +int lfs1_file_sync(lfs1_t *lfs1, lfs1_file_t *file); // Read data from file // // Takes a buffer and size indicating where to store the read data. // Returns the number of bytes read, or a negative error code on failure. -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, - void *buffer, lfs_size_t size); +lfs1_ssize_t lfs1_file_read(lfs1_t *lfs1, lfs1_file_t *file, + void *buffer, lfs1_size_t size); // Write data to file // @@ -392,38 +392,38 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, // 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); +lfs1_ssize_t lfs1_file_write(lfs1_t *lfs1, lfs1_file_t *file, + const void *buffer, lfs1_size_t size); // Change the position of the file // // The change in position is determined by the offset and whence flag. // Returns the old position of the file, or a negative error code on failure. -lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, - lfs_soff_t off, int whence); +lfs1_soff_t lfs1_file_seek(lfs1_t *lfs1, lfs1_file_t *file, + lfs1_soff_t off, int whence); // Truncates the size of the file to the specified size // // Returns a negative error code on failure. -int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); +int lfs1_file_truncate(lfs1_t *lfs1, lfs1_file_t *file, lfs1_off_t size); // Return the position of the file // -// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) +// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_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); +lfs1_soff_t lfs1_file_tell(lfs1_t *lfs1, lfs1_file_t *file); // Change the position of the file to the beginning of the file // -// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) +// Equivalent to lfs1_file_seek(lfs1, file, 0, LFS1_SEEK_CUR) // Returns a negative error code on failure. -int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); +int lfs1_file_rewind(lfs1_t *lfs1, lfs1_file_t *file); // Return the size of the file // -// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END) +// Similar to lfs1_file_seek(lfs1, file, 0, LFS1_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); +lfs1_soff_t lfs1_file_size(lfs1_t *lfs1, lfs1_file_t *file); /// Directory operations /// @@ -431,25 +431,25 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); // Create a directory // // Returns a negative error code on failure. -int lfs_mkdir(lfs_t *lfs, const char *path); +int lfs1_mkdir(lfs1_t *lfs1, const char *path); // Open a directory // // Once open a directory can be used with read to iterate over files. // Returns a negative error code on failure. -int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); +int lfs1_dir_open(lfs1_t *lfs1, lfs1_dir_t *dir, const char *path); // Close a directory // // Releases any allocated resources. // Returns a negative error code on failure. -int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); +int lfs1_dir_close(lfs1_t *lfs1, lfs1_dir_t *dir); // Read an entry in the directory // // Fills out the info structure, based on the specified file or directory. // Returns a negative error code on failure. -int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); +int lfs1_dir_read(lfs1_t *lfs1, lfs1_dir_t *dir, struct lfs1_info *info); // Change the position of the directory // @@ -457,7 +457,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 lfs1_dir_seek(lfs1_t *lfs1, lfs1_dir_t *dir, lfs1_off_t off); // Return the position of the directory // @@ -465,12 +465,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); +lfs1_soff_t lfs1_dir_tell(lfs1_t *lfs1, lfs1_dir_t *dir); // Change the position of the directory to the beginning of the directory // // Returns a negative error code on failure. -int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); +int lfs1_dir_rewind(lfs1_t *lfs1, lfs1_dir_t *dir); /// Miscellaneous littlefs specific operations /// @@ -482,7 +482,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); // blocks are in use or how much of the storage is available. // // Returns a negative error code on failure. -int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); +int lfs1_traverse(lfs1_t *lfs1, int (*cb)(void*, lfs1_block_t), void *data); // Prunes any recoverable errors that may have occured in the filesystem // @@ -491,7 +491,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); // allocation. // // Returns a negative error code on failure. -int lfs_deorphan(lfs_t *lfs); +int lfs1_deorphan(lfs1_t *lfs1); #ifdef __cplusplus diff --git a/lfs_util.c b/lfs1_util.c similarity index 83% rename from lfs_util.c rename to lfs1_util.c index 9ca0756..3832a5d 100644 --- a/lfs_util.c +++ b/lfs1_util.c @@ -1,17 +1,17 @@ /* - * lfs util functions + * lfs1 util functions * * Copyright (c) 2017, Arm Limited. All rights reserved. * SPDX-License-Identifier: BSD-3-Clause */ -#include "lfs_util.h" +#include "lfs1_util.h" // Only compile if user does not provide custom config -#ifndef LFS_CONFIG +#ifndef LFS1_CONFIG // Software CRC implementation with small lookup table -void lfs_crc(uint32_t *restrict crc, const void *buffer, size_t size) { +void lfs1_crc(uint32_t *restrict crc, const void *buffer, size_t size) { static const uint32_t rtable[16] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, diff --git a/lfs_util.h b/lfs1_util.h similarity index 57% rename from lfs_util.h rename to lfs1_util.h index b2dc237..b33b6a7 100644 --- a/lfs_util.h +++ b/lfs1_util.h @@ -1,22 +1,22 @@ /* - * lfs utility functions + * lfs1 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 LFS1_UTIL_H +#define LFS1_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 lfs1_util.h with their own configuration by defining +// LFS1_CONFIG as a header file to include (-DLFS1_CONFIG=lfs1_config.h). // -// If LFS_CONFIG is used, none of the default utils will be emitted and must be -// provided by the config file. To start I would suggest copying lfs_util.h and +// If LFS1_CONFIG is used, none of the default utils will be emitted and must be +// provided by the config file. To start I would suggest copying lfs1_util.h and // modifying as needed. -#ifdef LFS_CONFIG -#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) -#define LFS_STRINGIZE2(x) #x -#include LFS_STRINGIZE(LFS_CONFIG) +#ifdef LFS1_CONFIG +#define LFS1_STRINGIZE(x) LFS1_STRINGIZE2(x) +#define LFS1_STRINGIZE2(x) #x +#include LFS1_STRINGIZE(LFS1_CONFIG) #else // System includes @@ -24,13 +24,13 @@ #include #include -#ifndef LFS_NO_MALLOC +#ifndef LFS1_NO_MALLOC #include #endif -#ifndef LFS_NO_ASSERT +#ifndef LFS1_NO_ASSERT #include #endif -#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) +#if !defined(LFS1_NO_DEBUG) || !defined(LFS1_NO_WARN) || !defined(LFS1_NO_ERROR) #include #endif @@ -45,51 +45,51 @@ extern "C" // code footprint // Logging functions -#ifndef LFS_NO_DEBUG -#define LFS_DEBUG(fmt, ...) \ - printf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#ifndef LFS1_NO_DEBUG +#define LFS1_DEBUG(fmt, ...) \ + printf("lfs1 debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) #else -#define LFS_DEBUG(fmt, ...) +#define LFS1_DEBUG(fmt, ...) #endif -#ifndef LFS_NO_WARN -#define LFS_WARN(fmt, ...) \ - printf("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#ifndef LFS1_NO_WARN +#define LFS1_WARN(fmt, ...) \ + printf("lfs1 warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) #else -#define LFS_WARN(fmt, ...) +#define LFS1_WARN(fmt, ...) #endif -#ifndef LFS_NO_ERROR -#define LFS_ERROR(fmt, ...) \ - printf("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#ifndef LFS1_NO_ERROR +#define LFS1_ERROR(fmt, ...) \ + printf("lfs1 error:%d: " fmt "\n", __LINE__, __VA_ARGS__) #else -#define LFS_ERROR(fmt, ...) +#define LFS1_ERROR(fmt, ...) #endif // Runtime assertions -#ifndef LFS_NO_ASSERT -#define LFS_ASSERT(test) assert(test) +#ifndef LFS1_NO_ASSERT +#define LFS1_ASSERT(test) assert(test) #else -#define LFS_ASSERT(test) +#define LFS1_ASSERT(test) #endif // Builtin functions, these may be replaced by more efficient -// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more +// toolchain-specific implementations. LFS1_NO_INTRINSICS falls back to a more // expensive basic C implementation for debugging purposes // Min/max functions for unsigned 32-bit numbers -static inline uint32_t lfs_max(uint32_t a, uint32_t b) { +static inline uint32_t lfs1_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 lfs1_min(uint32_t a, uint32_t b) { return (a < b) ? a : b; } // Find the next smallest power of 2 less than or equal to a -static inline uint32_t lfs_npw2(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) +static inline uint32_t lfs1_npw2(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) return 32 - __builtin_clz(a-1); #else uint32_t r = 0; @@ -104,18 +104,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__) +// lfs1_ctz(0) may be undefined +static inline uint32_t lfs1_ctz(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && defined(__GNUC__) return __builtin_ctz(a); #else - return lfs_npw2((a & -a) + 1) - 1; + return lfs1_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 lfs1_popc(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) return __builtin_popcount(a); #else a = a - ((a >> 1) & 0x55555555); @@ -126,18 +126,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 lfs1_scmp(uint32_t a, uint32_t b) { return (int)(unsigned)(a - b); } // Convert from 32-bit little-endian to native order -static inline uint32_t lfs_fromle32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ +static inline uint32_t lfs1_fromle32(uint32_t a) { +#if !defined(LFS1_NO_INTRINSICS) && ( \ (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) return a; -#elif !defined(LFS_NO_INTRINSICS) && ( \ +#elif !defined(LFS1_NO_INTRINSICS) && ( \ (defined( BYTE_ORDER ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ (defined(__BYTE_ORDER ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) @@ -151,16 +151,16 @@ static inline uint32_t lfs_fromle32(uint32_t a) { } // Convert to 32-bit little-endian from native order -static inline uint32_t lfs_tole32(uint32_t a) { - return lfs_fromle32(a); +static inline uint32_t lfs1_tole32(uint32_t a) { + return lfs1_fromle32(a); } // Calculate CRC-32 with polynomial = 0x04c11db7 -void lfs_crc(uint32_t *crc, const void *buffer, size_t size); +void lfs1_crc(uint32_t *crc, const void *buffer, size_t size); // Allocate memory, only used if buffers are not provided to littlefs -static inline void *lfs_malloc(size_t size) { -#ifndef LFS_NO_MALLOC +static inline void *lfs1_malloc(size_t size) { +#ifndef LFS1_NO_MALLOC return malloc(size); #else (void)size; @@ -169,8 +169,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 lfs1_free(void *p) { +#ifndef LFS1_NO_MALLOC free(p); #else (void)p; diff --git a/scripts/prefix.py b/scripts/prefix.py index ca547b6..da04740 100755 --- a/scripts/prefix.py +++ b/scripts/prefix.py @@ -5,7 +5,7 @@ # conflict at compile time. # # example: -# $ ./scripts/prefix.py lfs2 +# $ ./scripts/prefix.py lfs12 import os import os.path @@ -16,7 +16,7 @@ import tempfile import shutil import subprocess -DEFAULT_PREFIX = "lfs" +DEFAULT_PREFIX = "lfs1" def subn(from_prefix, to_prefix, name): name, count1 = re.subn('\\b'+from_prefix, to_prefix, name) diff --git a/tests/template.fmt b/tests/template.fmt index a53f0c7..760f217 100644 --- a/tests/template.fmt +++ b/tests/template.fmt @@ -1,6 +1,6 @@ /// AUTOGENERATED TEST /// -#include "lfs.h" -#include "emubd/lfs_emubd.h" +#include "lfs1.h" +#include "emubd/lfs1_emubd.h" #include #include #include @@ -37,7 +37,7 @@ static void test_assert(const char *file, unsigned line, // utility functions for traversals -static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{ +static int __attribute__((used)) test_count(void *p, lfs1_block_t b) {{ (void)b; unsigned *u = (unsigned*)p; *u += 1; @@ -45,62 +45,62 @@ static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{ }} -// lfs declarations -lfs_t lfs; -lfs_emubd_t bd; -lfs_file_t file[4]; -lfs_dir_t dir[4]; -struct lfs_info info; +// lfs1 declarations +lfs1_t lfs1; +lfs1_emubd_t bd; +lfs1_file_t file[4]; +lfs1_dir_t dir[4]; +struct lfs1_info info; uint8_t buffer[1024]; uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; -lfs_size_t size; -lfs_size_t wsize; -lfs_size_t rsize; +lfs1_size_t size; +lfs1_size_t wsize; +lfs1_size_t rsize; uintmax_t test; -#ifndef LFS_READ_SIZE -#define LFS_READ_SIZE 16 +#ifndef LFS1_READ_SIZE +#define LFS1_READ_SIZE 16 #endif -#ifndef LFS_PROG_SIZE -#define LFS_PROG_SIZE 16 +#ifndef LFS1_PROG_SIZE +#define LFS1_PROG_SIZE 16 #endif -#ifndef LFS_BLOCK_SIZE -#define LFS_BLOCK_SIZE 512 +#ifndef LFS1_BLOCK_SIZE +#define LFS1_BLOCK_SIZE 512 #endif -#ifndef LFS_BLOCK_COUNT -#define LFS_BLOCK_COUNT 1024 +#ifndef LFS1_BLOCK_COUNT +#define LFS1_BLOCK_COUNT 1024 #endif -#ifndef LFS_LOOKAHEAD -#define LFS_LOOKAHEAD 128 +#ifndef LFS1_LOOKAHEAD +#define LFS1_LOOKAHEAD 128 #endif -const struct lfs_config cfg = {{ +const struct lfs1_config cfg = {{ .context = &bd, - .read = &lfs_emubd_read, - .prog = &lfs_emubd_prog, - .erase = &lfs_emubd_erase, - .sync = &lfs_emubd_sync, + .read = &lfs1_emubd_read, + .prog = &lfs1_emubd_prog, + .erase = &lfs1_emubd_erase, + .sync = &lfs1_emubd_sync, - .read_size = LFS_READ_SIZE, - .prog_size = LFS_PROG_SIZE, - .block_size = LFS_BLOCK_SIZE, - .block_count = LFS_BLOCK_COUNT, - .lookahead = LFS_LOOKAHEAD, + .read_size = LFS1_READ_SIZE, + .prog_size = LFS1_PROG_SIZE, + .block_size = LFS1_BLOCK_SIZE, + .block_count = LFS1_BLOCK_COUNT, + .lookahead = LFS1_LOOKAHEAD, }}; // Entry point int main(void) {{ - lfs_emubd_create(&cfg, "blocks"); + lfs1_emubd_create(&cfg, "blocks"); {tests} - lfs_emubd_destroy(&cfg); + lfs1_emubd_destroy(&cfg); }} diff --git a/tests/test.py b/tests/test.py index 24b0d1a..bfeec46 100755 --- a/tests/test.py +++ b/tests/test.py @@ -28,7 +28,7 @@ def generate(test): # Remove build artifacts to force rebuild try: os.remove('test.o') - os.remove('lfs') + os.remove('lfs1') except OSError: pass @@ -39,9 +39,9 @@ def compile(): def execute(): if 'EXEC' in os.environ: - subprocess.check_call([os.environ['EXEC'], "./lfs"]) + subprocess.check_call([os.environ['EXEC'], "./lfs1"]) else: - subprocess.check_call(["./lfs"]) + subprocess.check_call(["./lfs1"]) def main(test=None): if test and not test.startswith('-'): diff --git a/tests/test_alloc.sh b/tests/test_alloc.sh index 6b3b181..8ccea8d 100755 --- a/tests/test_alloc.sh +++ b/tests/test_alloc.sh @@ -4,424 +4,424 @@ set -eu echo "=== Allocator tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST SIZE=15000 -lfs_mkdir() { +lfs1_mkdir() { tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "$1") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "$1") => 0; + lfs1_unmount(&lfs1) => 0; TEST } -lfs_remove() { +lfs1_remove() { tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "$1/eggs") => 0; - lfs_remove(&lfs, "$1/bacon") => 0; - lfs_remove(&lfs, "$1/pancakes") => 0; - lfs_remove(&lfs, "$1") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "$1/eggs") => 0; + lfs1_remove(&lfs1, "$1/bacon") => 0; + lfs1_remove(&lfs1, "$1/pancakes") => 0; + lfs1_remove(&lfs1, "$1") => 0; + lfs1_unmount(&lfs1) => 0; TEST } -lfs_alloc_singleproc() { +lfs1_alloc_singleproc() { tests/test.py << TEST const char *names[] = {"bacon", "eggs", "pancakes"}; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { sprintf((char*)buffer, "$1/%s", names[n]); - lfs_file_open(&lfs, &file[n], (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + lfs1_file_open(&lfs1, &file[n], (char*)buffer, + LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_APPEND) => 0; } for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { size = strlen(names[n]); for (int i = 0; i < $SIZE; i++) { - lfs_file_write(&lfs, &file[n], names[n], size) => size; + lfs1_file_write(&lfs1, &file[n], names[n], size) => size; } } for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { - lfs_file_close(&lfs, &file[n]) => 0; + lfs1_file_close(&lfs1, &file[n]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST } -lfs_alloc_multiproc() { +lfs1_alloc_multiproc() { for name in bacon eggs pancakes do tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "$1/$name", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "$1/$name", + LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_APPEND) => 0; size = strlen("$name"); memcpy(buffer, "$name", size); for (int i = 0; i < $SIZE; i++) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST done } -lfs_verify() { +lfs1_verify() { for name in bacon eggs pancakes do tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "$1/$name", LFS_O_RDONLY) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "$1/$name", LFS1_O_RDONLY) => 0; size = strlen("$name"); for (int i = 0; i < $SIZE; i++) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "$name", size) => 0; } - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST done } echo "--- Single-process allocation test ---" -lfs_mkdir singleproc -lfs_alloc_singleproc singleproc -lfs_verify singleproc +lfs1_mkdir singleproc +lfs1_alloc_singleproc singleproc +lfs1_verify singleproc echo "--- Multi-process allocation test ---" -lfs_mkdir multiproc -lfs_alloc_multiproc multiproc -lfs_verify multiproc -lfs_verify singleproc +lfs1_mkdir multiproc +lfs1_alloc_multiproc multiproc +lfs1_verify multiproc +lfs1_verify singleproc echo "--- Single-process reuse test ---" -lfs_remove singleproc -lfs_mkdir singleprocreuse -lfs_alloc_singleproc singleprocreuse -lfs_verify singleprocreuse -lfs_verify multiproc +lfs1_remove singleproc +lfs1_mkdir singleprocreuse +lfs1_alloc_singleproc singleprocreuse +lfs1_verify singleprocreuse +lfs1_verify multiproc echo "--- Multi-process reuse test ---" -lfs_remove multiproc -lfs_mkdir multiprocreuse -lfs_alloc_singleproc multiprocreuse -lfs_verify multiprocreuse -lfs_verify singleprocreuse +lfs1_remove multiproc +lfs1_mkdir multiprocreuse +lfs1_alloc_singleproc multiprocreuse +lfs1_verify multiprocreuse +lfs1_verify singleprocreuse echo "--- Cleanup ---" -lfs_remove multiprocreuse -lfs_remove singleprocreuse +lfs1_remove multiprocreuse +lfs1_remove singleprocreuse echo "--- Exhaustion test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("exhaustion"); memcpy(buffer, "exhaustion", size); - lfs_file_write(&lfs, &file[0], buffer, size) => size; - lfs_file_sync(&lfs, &file[0]) => 0; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; + lfs1_file_sync(&lfs1, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - lfs_ssize_t res; + lfs1_ssize_t res; while (true) { - res = lfs_file_write(&lfs, &file[0], buffer, size); + res = lfs1_file_write(&lfs1, &file[0], buffer, size); if (res < 0) { break; } res => size; } - res => LFS_ERR_NOSPC; + res => LFS1_ERR_NOSPC; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_RDONLY); size = strlen("exhaustion"); - lfs_file_size(&lfs, &file[0]) => size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_size(&lfs1, &file[0]) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "exhaustion", size) => 0; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Exhaustion wraparound test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "exhaustion") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "exhaustion") => 0; - lfs_file_open(&lfs, &file[0], "padding", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_file_open(&lfs1, &file[0], "padding", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("buffering"); memcpy(buffer, "buffering", size); for (int i = 0; i < $SIZE; i++) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; - lfs_remove(&lfs, "padding") => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_remove(&lfs1, "padding") => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("exhaustion"); memcpy(buffer, "exhaustion", size); - lfs_file_write(&lfs, &file[0], buffer, size) => size; - lfs_file_sync(&lfs, &file[0]) => 0; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; + lfs1_file_sync(&lfs1, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - lfs_ssize_t res; + lfs1_ssize_t res; while (true) { - res = lfs_file_write(&lfs, &file[0], buffer, size); + res = lfs1_file_write(&lfs1, &file[0], buffer, size); if (res < 0) { break; } res => size; } - res => LFS_ERR_NOSPC; + res => LFS1_ERR_NOSPC; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_RDONLY); + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_RDONLY); size = strlen("exhaustion"); - lfs_file_size(&lfs, &file[0]) => size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_size(&lfs1, &file[0]) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "exhaustion", size) => 0; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Dir exhaustion test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "exhaustion") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "exhaustion") => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < (cfg.block_count-6)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_mkdir(&lfs, "exhaustiondir") => 0; - lfs_remove(&lfs, "exhaustiondir") => 0; + lfs1_mkdir(&lfs1, "exhaustiondir") => 0; + lfs1_remove(&lfs1, "exhaustiondir") => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_APPEND); + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_APPEND); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < (cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; - lfs_unmount(&lfs) => 0; + lfs1_mkdir(&lfs1, "exhaustiondir") => LFS1_ERR_NOSPC; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Chained dir exhaustion test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "exhaustion") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "exhaustion") => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < (cfg.block_count-24)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; for (int i = 0; i < 9; i++) { sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i); - lfs_mkdir(&lfs, (char*)buffer) => 0; + lfs1_mkdir(&lfs1, (char*)buffer) => 0; } - lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; + lfs1_mkdir(&lfs1, "exhaustiondir") => LFS1_ERR_NOSPC; - lfs_remove(&lfs, "exhaustion") => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_remove(&lfs1, "exhaustion") => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < (cfg.block_count-26)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_mkdir(&lfs, "exhaustiondir") => 0; - lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; + lfs1_mkdir(&lfs1, "exhaustiondir") => 0; + lfs1_mkdir(&lfs1, "exhaustiondir2") => LFS1_ERR_NOSPC; TEST echo "--- Split dir test ---" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; // create one block whole for half a directory - lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file[0], (void*)"hi", 2) => 2; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_open(&lfs1, &file[0], "bump", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_write(&lfs1, &file[0], (void*)"hi", 2) => 2; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); + lfs1_file_open(&lfs1, &file[0], "exhaustion", LFS1_O_WRONLY | LFS1_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < (cfg.block_count-6)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; // open hole - lfs_remove(&lfs, "bump") => 0; + lfs1_remove(&lfs1, "bump") => 0; - lfs_mkdir(&lfs, "splitdir") => 0; - lfs_file_open(&lfs, &file[0], "splitdir/bump", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file[0], buffer, size) => LFS_ERR_NOSPC; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_mkdir(&lfs1, "splitdir") => 0; + lfs1_file_open(&lfs1, &file[0], "splitdir/bump", + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_write(&lfs1, &file[0], buffer, size) => LFS1_ERR_NOSPC; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Outdated lookahead test ---" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; // fill completely with two files - lfs_file_open(&lfs, &file[0], "exhaustion1", - LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion1", + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4)/2)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_file_open(&lfs, &file[0], "exhaustion2", - LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion2", + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; // remount to force reset of lookahead - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; // rewrite one file - lfs_file_open(&lfs, &file[0], "exhaustion1", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_sync(&lfs, &file[0]) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion1", + LFS1_O_WRONLY | LFS1_O_TRUNC) => 0; + lfs1_file_sync(&lfs1, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4)/2)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; // rewrite second file, this requires lookahead does not // use old population - lfs_file_open(&lfs, &file[0], "exhaustion2", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_sync(&lfs, &file[0]) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion2", + LFS1_O_WRONLY | LFS1_O_TRUNC) => 0; + lfs1_file_sync(&lfs1, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; TEST echo "--- Outdated lookahead and split dir test ---" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; // fill completely with two files - lfs_file_open(&lfs, &file[0], "exhaustion1", - LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion1", + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4)/2)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_file_open(&lfs, &file[0], "exhaustion2", - LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion2", + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4+1)/2)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; // remount to force reset of lookahead - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; // rewrite one file with a hole of one block - lfs_file_open(&lfs, &file[0], "exhaustion1", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_sync(&lfs, &file[0]) => 0; + lfs1_file_open(&lfs1, &file[0], "exhaustion1", + LFS1_O_WRONLY | LFS1_O_TRUNC) => 0; + lfs1_file_sync(&lfs1, &file[0]) => 0; size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; + for (lfs1_size_t i = 0; i < ((cfg.block_count-4)/2 - 1)*(cfg.block_size-8); i += size) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; // try to allocate a directory, should fail! - lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; + lfs1_mkdir(&lfs1, "split") => LFS1_ERR_NOSPC; // file should not fail - lfs_file_open(&lfs, &file[0], "notasplit", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file[0], "hi", 2) => 2; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_open(&lfs1, &file[0], "notasplit", + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_write(&lfs1, &file[0], "hi", 2) => 2; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_corrupt.sh b/tests/test_corrupt.sh index 44f1cae..6277ebd 100755 --- a/tests/test_corrupt.sh +++ b/tests/test_corrupt.sh @@ -6,71 +6,71 @@ echo "=== Corrupt tests ===" NAMEMULT=64 FILEMULT=1 -lfs_mktree() { +lfs1_mktree() { tests/test.py ${1:-} << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (int i = 1; i < 10; i++) { for (int j = 0; j < $NAMEMULT; j++) { buffer[j] = '0'+i; } buffer[$NAMEMULT] = '\0'; - lfs_mkdir(&lfs, (char*)buffer) => 0; + lfs1_mkdir(&lfs1, (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[0], (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], (char*)buffer, + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = $NAMEMULT; for (int j = 0; j < i*$FILEMULT; j++) { - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST } -lfs_chktree() { +lfs1_chktree() { tests/test.py ${1:-} << TEST - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &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; + lfs1_stat(&lfs1, (char*)buffer, &info) => 0; + info.type => LFS1_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[0], (char*)buffer, LFS_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[0], (char*)buffer, LFS1_O_RDONLY) => 0; size = $NAMEMULT; for (int j = 0; j < i*$FILEMULT; j++) { - lfs_file_read(&lfs, &file[0], rbuffer, size) => size; + lfs1_file_read(&lfs1, &file[0], rbuffer, size) => size; memcmp(buffer, rbuffer, size) => 0; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST } echo "--- Sanity check ---" rm -rf blocks -lfs_mktree -lfs_chktree +lfs1_mktree +lfs1_chktree echo "--- Block corruption ---" for i in {0..33} @@ -78,8 +78,8 @@ do rm -rf blocks mkdir blocks ln -s /dev/zero blocks/$(printf '%x' $i) - lfs_mktree - lfs_chktree + lfs1_mktree + lfs1_chktree done echo "--- Block persistance ---" @@ -87,10 +87,10 @@ for i in {0..33} do rm -rf blocks mkdir blocks - lfs_mktree + lfs1_mktree chmod a-w blocks/$(printf '%x' $i) - lfs_mktree - lfs_chktree + lfs1_mktree + lfs1_chktree done echo "--- Big region corruption ---" @@ -100,8 +100,8 @@ for i in {2..255} do ln -s /dev/zero blocks/$(printf '%x' $i) done -lfs_mktree -lfs_chktree +lfs1_mktree +lfs1_chktree echo "--- Alternating corruption ---" rm -rf blocks @@ -110,8 +110,8 @@ for i in {2..511..2} do ln -s /dev/zero blocks/$(printf '%x' $i) done -lfs_mktree -lfs_chktree +lfs1_mktree +lfs1_chktree echo "--- Results ---" tests/stats.py diff --git a/tests/test_dirs.sh b/tests/test_dirs.sh index 874808d..e442f27 100755 --- a/tests/test_dirs.sh +++ b/tests/test_dirs.sh @@ -6,294 +6,294 @@ LARGESIZE=128 echo "=== Directory tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST echo "--- Root directory ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Directory creation ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "potato") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "potato") => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- File creation ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "burito", LFS1_O_CREAT | LFS1_O_WRONLY) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Directory iteration ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "potato") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "burito") => 0; - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_REG; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Directory failures ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; - lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERR_NOTDIR; - lfs_file_open(&lfs, &file[0], "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file[0], "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "potato") => LFS1_ERR_EXIST; + lfs1_dir_open(&lfs1, &dir[0], "tomato") => LFS1_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "burito") => LFS1_ERR_NOTDIR; + lfs1_file_open(&lfs1, &file[0], "tomato", LFS1_O_RDONLY) => LFS1_ERR_NOENT; + lfs1_file_open(&lfs1, &file[0], "potato", LFS1_O_RDONLY) => LFS1_ERR_ISDIR; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Nested directories ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "potato/baked") => 0; - lfs_mkdir(&lfs, "potato/sweet") => 0; - lfs_mkdir(&lfs, "potato/fried") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "potato/baked") => 0; + lfs1_mkdir(&lfs1, "potato/sweet") => 0; + lfs1_mkdir(&lfs1, "potato/fried") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "potato") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "potato") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "baked") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "sweet") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "fried") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Multi-block directory ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "cactus") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "cactus") => 0; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "cactus/test%d", i); - lfs_mkdir(&lfs, (char*)buffer) => 0; + lfs1_mkdir(&lfs1, (char*)buffer) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "cactus") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "cactus") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; + info.type => LFS1_TYPE_DIR; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "test%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - info.type => LFS_TYPE_DIR; + info.type => LFS1_TYPE_DIR; } - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Directory remove ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "potato/sweet") => 0; - lfs_remove(&lfs, "potato/baked") => 0; - lfs_remove(&lfs, "potato/fried") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "potato") => LFS1_ERR_NOTEMPTY; + lfs1_remove(&lfs1, "potato/sweet") => 0; + lfs1_remove(&lfs1, "potato/baked") => 0; + lfs1_remove(&lfs1, "potato/fried") => 0; - lfs_dir_open(&lfs, &dir[0], "potato") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "potato") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; - lfs_remove(&lfs, "potato") => 0; + lfs1_remove(&lfs1, "potato") => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "burito") => 0; - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_REG; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "cactus") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "burito") => 0; - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_REG; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "cactus") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Directory rename ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "coldpotato") => 0; - lfs_mkdir(&lfs, "coldpotato/baked") => 0; - lfs_mkdir(&lfs, "coldpotato/sweet") => 0; - lfs_mkdir(&lfs, "coldpotato/fried") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "coldpotato") => 0; + lfs1_mkdir(&lfs1, "coldpotato/baked") => 0; + lfs1_mkdir(&lfs1, "coldpotato/sweet") => 0; + lfs1_mkdir(&lfs1, "coldpotato/fried") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "coldpotato", "hotpotato") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "hotpotato") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "hotpotato") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "baked") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "sweet") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "fried") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "warmpotato") => 0; - lfs_mkdir(&lfs, "warmpotato/mushy") => 0; - lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERR_NOTEMPTY; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "warmpotato") => 0; + lfs1_mkdir(&lfs1, "warmpotato/mushy") => 0; + lfs1_rename(&lfs1, "hotpotato", "warmpotato") => LFS1_ERR_NOTEMPTY; - lfs_remove(&lfs, "warmpotato/mushy") => 0; - lfs_rename(&lfs, "hotpotato", "warmpotato") => 0; + lfs1_remove(&lfs1, "warmpotato/mushy") => 0; + lfs1_rename(&lfs1, "hotpotato", "warmpotato") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "warmpotato") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "warmpotato") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "baked") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "sweet") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "fried") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "coldpotato") => 0; - lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; - lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; - lfs_rename(&lfs, "warmpotato/fried", "coldpotato/fried") => 0; - lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "warmpotato") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "coldpotato") => 0; + lfs1_rename(&lfs1, "warmpotato/baked", "coldpotato/baked") => 0; + lfs1_rename(&lfs1, "warmpotato/sweet", "coldpotato/sweet") => 0; + lfs1_rename(&lfs1, "warmpotato/fried", "coldpotato/fried") => 0; + lfs1_remove(&lfs1, "coldpotato") => LFS1_ERR_NOTEMPTY; + lfs1_remove(&lfs1, "warmpotato") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "coldpotato") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "baked") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "sweet") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "fried") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Recursive remove ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "coldpotato") => LFS1_ERR_NOTEMPTY; - lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "coldpotato") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; while (true) { - int err = lfs_dir_read(&lfs, &dir[0], &info); + int err = lfs1_dir_read(&lfs1, &dir[0], &info); err >= 0 => 1; if (err == 0) { break; @@ -301,183 +301,183 @@ tests/test.py << TEST strcpy((char*)buffer, "coldpotato/"); strcat((char*)buffer, info.name); - lfs_remove(&lfs, (char*)buffer) => 0; + lfs1_remove(&lfs1, (char*)buffer) => 0; } - lfs_remove(&lfs, "coldpotato") => 0; + lfs1_remove(&lfs1, "coldpotato") => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "burito") => 0; - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_REG; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "cactus") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Multi-block rename ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "cactus/test%d", i); sprintf((char*)wbuffer, "cactus/tedd%d", i); - lfs_rename(&lfs, (char*)buffer, (char*)wbuffer) => 0; + lfs1_rename(&lfs1, (char*)buffer, (char*)wbuffer) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "cactus") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "cactus") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; + info.type => LFS1_TYPE_DIR; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "tedd%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - info.type => LFS_TYPE_DIR; + info.type => LFS1_TYPE_DIR; } - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Multi-block remove ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "cactus") => LFS1_ERR_NOTEMPTY; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "cactus/tedd%d", i); - lfs_remove(&lfs, (char*)buffer) => 0; + lfs1_remove(&lfs1, (char*)buffer) => 0; } - lfs_remove(&lfs, "cactus") => 0; - lfs_unmount(&lfs) => 0; + lfs1_remove(&lfs1, "cactus") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "burito") => 0; - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_REG; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Multi-block directory with files ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "prickly-pear") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "prickly-pear") => 0; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "prickly-pear/test%d", i); - lfs_file_open(&lfs, &file[0], (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], (char*)buffer, + LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = 6; memcpy(wbuffer, "Hello", size); - lfs_file_write(&lfs, &file[0], wbuffer, size) => size; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_write(&lfs1, &file[0], wbuffer, size) => size; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "prickly-pear") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; + info.type => LFS1_TYPE_DIR; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "test%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 6; } - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Multi-block rename with files ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "prickly-pear/test%d", i); sprintf((char*)wbuffer, "prickly-pear/tedd%d", i); - lfs_rename(&lfs, (char*)buffer, (char*)wbuffer) => 0; + lfs1_rename(&lfs1, (char*)buffer, (char*)wbuffer) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "prickly-pear") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; + info.type => LFS1_TYPE_DIR; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "tedd%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 6; } - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Multi-block remove with files ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_remove(&lfs1, "prickly-pear") => LFS1_ERR_NOTEMPTY; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "prickly-pear/tedd%d", i); - lfs_remove(&lfs, (char*)buffer) => 0; + lfs1_remove(&lfs1, (char*)buffer) => 0; } - lfs_remove(&lfs, "prickly-pear") => 0; - lfs_unmount(&lfs) => 0; + lfs1_remove(&lfs1, "prickly-pear") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "burito") => 0; - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + info.type => LFS1_TYPE_REG; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_files.sh b/tests/test_files.sh index bbecea9..94b481f 100755 --- a/tests/test_files.sh +++ b/tests/test_files.sh @@ -8,65 +8,65 @@ LARGESIZE=262144 echo "=== File tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST echo "--- Simple file test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = strlen("Hello World!\n"); memcpy(wbuffer, "Hello World!\n", size); - lfs_file_write(&lfs, &file[0], wbuffer, size) => size; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_write(&lfs1, &file[0], wbuffer, size) => size; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_file_open(&lfs, &file[0], "hello", LFS_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[0], "hello", LFS1_O_RDONLY) => 0; size = strlen("Hello World!\n"); - lfs_file_read(&lfs, &file[0], rbuffer, size) => size; + lfs1_file_read(&lfs1, &file[0], rbuffer, size) => size; memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST w_test() { tests/test.py << TEST size = $1; - lfs_size_t chunk = 31; + lfs1_size_t chunk = 31; srand(0); - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "$2", - ${3:-LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC}) => 0; - for (lfs_size_t i = 0; i < size; i += chunk) { + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "$2", + ${3:-LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_TRUNC}) => 0; + for (lfs1_size_t i = 0; i < size; i += chunk) { chunk = (chunk < size - i) ? chunk : size - i; - for (lfs_size_t b = 0; b < chunk; b++) { + for (lfs1_size_t b = 0; b < chunk; b++) { buffer[b] = rand() & 0xff; } - lfs_file_write(&lfs, &file[0], buffer, chunk) => chunk; + lfs1_file_write(&lfs1, &file[0], buffer, chunk) => chunk; } - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST } r_test() { tests/test.py << TEST size = $1; - lfs_size_t chunk = 29; + lfs1_size_t chunk = 29; srand(0); - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "$2", &info) => 0; - info.type => LFS_TYPE_REG; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "$2", &info) => 0; + info.type => LFS1_TYPE_REG; info.size => size; - lfs_file_open(&lfs, &file[0], "$2", ${3:-LFS_O_RDONLY}) => 0; - for (lfs_size_t i = 0; i < size; i += chunk) { + lfs1_file_open(&lfs1, &file[0], "$2", ${3:-LFS1_O_RDONLY}) => 0; + for (lfs1_size_t i = 0; i < size; i += chunk) { chunk = (chunk < size - i) ? chunk : size - i; - lfs_file_read(&lfs, &file[0], buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk && i+b < size; b++) { + lfs1_file_read(&lfs1, &file[0], buffer, chunk) => chunk; + for (lfs1_size_t b = 0; b < chunk && i+b < size; b++) { buffer[b] => rand() & 0xff; } } - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST } @@ -106,52 +106,52 @@ r_test 0 noavacado echo "--- Dir check ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; - lfs_dir_read(&lfs, &dir[0], &info) => 1; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hello") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => strlen("Hello World!\n"); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "smallavacado") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => $SMALLSIZE; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "mediumavacado") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => $MEDIUMSIZE; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "largeavacado") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => $LARGESIZE; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "noavacado") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Many file test ---" tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST tests/test.py << TEST // Create 300 files of 6 bytes - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "directory") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "directory") => 0; for (unsigned i = 0; i < 300; i++) { snprintf((char*)buffer, sizeof(buffer), "file_%03d", i); - lfs_file_open(&lfs, &file[0], (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[0], (char*)buffer, LFS1_O_WRONLY | LFS1_O_CREAT) => 0; size = 6; memcpy(wbuffer, "Hello", size); - lfs_file_write(&lfs, &file[0], wbuffer, size) => size; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_write(&lfs1, &file[0], wbuffer, size) => size; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_format.sh b/tests/test_format.sh index b907101..c1e56fd 100755 --- a/tests/test_format.sh +++ b/tests/test_format.sh @@ -6,43 +6,43 @@ rm -rf blocks echo "--- Basic formatting ---" tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST echo "--- Invalid superblocks ---" ln -f -s /dev/zero blocks/0 ln -f -s /dev/zero blocks/1 tests/test.py << TEST - lfs_format(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs1_format(&lfs1, &cfg) => LFS1_ERR_CORRUPT; TEST rm blocks/0 blocks/1 echo "--- Basic mounting ---" tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Invalid mount ---" tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST rm blocks/0 blocks/1 tests/test.py << TEST - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs1_mount(&lfs1, &cfg) => LFS1_ERR_CORRUPT; TEST echo "--- Valid corrupt mount ---" tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST rm blocks/0 tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_interspersed.sh b/tests/test_interspersed.sh index 52e24bc..c4233fd 100755 --- a/tests/test_interspersed.sh +++ b/tests/test_interspersed.sh @@ -4,182 +4,182 @@ set -eu echo "=== Interspersed tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST echo "--- Interspersed file test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_open(&lfs, &file[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_open(&lfs, &file[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_open(&lfs, &file[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "a", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[1], "b", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[2], "c", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[3], "d", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; for (int i = 0; i < 10; i++) { - lfs_file_write(&lfs, &file[0], (const void*)"a", 1) => 1; - lfs_file_write(&lfs, &file[1], (const void*)"b", 1) => 1; - lfs_file_write(&lfs, &file[2], (const void*)"c", 1) => 1; - lfs_file_write(&lfs, &file[3], (const void*)"d", 1) => 1; + lfs1_file_write(&lfs1, &file[0], (const void*)"a", 1) => 1; + lfs1_file_write(&lfs1, &file[1], (const void*)"b", 1) => 1; + lfs1_file_write(&lfs1, &file[2], (const void*)"c", 1) => 1; + lfs1_file_write(&lfs1, &file[3], (const void*)"d", 1) => 1; } - lfs_file_close(&lfs, &file[0]); - lfs_file_close(&lfs, &file[1]); - lfs_file_close(&lfs, &file[2]); - lfs_file_close(&lfs, &file[3]); + lfs1_file_close(&lfs1, &file[0]); + lfs1_file_close(&lfs1, &file[1]); + lfs1_file_close(&lfs1, &file[2]); + lfs1_file_close(&lfs1, &file[3]); - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "a") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "b") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "c") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "d") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; - lfs_file_open(&lfs, &file[0], "a", LFS_O_RDONLY) => 0; - lfs_file_open(&lfs, &file[1], "b", LFS_O_RDONLY) => 0; - lfs_file_open(&lfs, &file[2], "c", LFS_O_RDONLY) => 0; - lfs_file_open(&lfs, &file[3], "d", LFS_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[0], "a", LFS1_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[1], "b", LFS1_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[2], "c", LFS1_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[3], "d", LFS1_O_RDONLY) => 0; for (int i = 0; i < 10; i++) { - lfs_file_read(&lfs, &file[0], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[0], buffer, 1) => 1; buffer[0] => 'a'; - lfs_file_read(&lfs, &file[1], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[1], buffer, 1) => 1; buffer[0] => 'b'; - lfs_file_read(&lfs, &file[2], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[2], buffer, 1) => 1; buffer[0] => 'c'; - lfs_file_read(&lfs, &file[3], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[3], buffer, 1) => 1; buffer[0] => 'd'; } - lfs_file_close(&lfs, &file[0]); - lfs_file_close(&lfs, &file[1]); - lfs_file_close(&lfs, &file[2]); - lfs_file_close(&lfs, &file[3]); + lfs1_file_close(&lfs1, &file[0]); + lfs1_file_close(&lfs1, &file[1]); + lfs1_file_close(&lfs1, &file[2]); + lfs1_file_close(&lfs1, &file[3]); - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Interspersed remove file test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; + lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1; } - lfs_remove(&lfs, "a") => 0; - lfs_remove(&lfs, "b") => 0; - lfs_remove(&lfs, "c") => 0; - lfs_remove(&lfs, "d") => 0; + lfs1_remove(&lfs1, "a") => 0; + lfs1_remove(&lfs1, "b") => 0; + lfs1_remove(&lfs1, "c") => 0; + lfs1_remove(&lfs1, "d") => 0; for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; + lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1; } - lfs_file_close(&lfs, &file[0]); + lfs1_file_close(&lfs1, &file[0]); - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "e") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; - lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_RDONLY) => 0; for (int i = 0; i < 10; i++) { - lfs_file_read(&lfs, &file[0], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[0], buffer, 1) => 1; buffer[0] => 'e'; } - lfs_file_close(&lfs, &file[0]); + lfs1_file_close(&lfs1, &file[0]); - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Remove inconveniently test ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &file[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_open(&lfs, &file[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_WRONLY | LFS1_O_TRUNC) => 0; + lfs1_file_open(&lfs1, &file[1], "f", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; + lfs1_file_open(&lfs1, &file[2], "g", LFS1_O_WRONLY | LFS1_O_CREAT) => 0; for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; - lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1; - lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1; + lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1; + lfs1_file_write(&lfs1, &file[1], (const void*)"f", 1) => 1; + lfs1_file_write(&lfs1, &file[2], (const void*)"g", 1) => 1; } - lfs_remove(&lfs, "f") => 0; + lfs1_remove(&lfs1, "f") => 0; for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file[0], (const void*)"e", 1) => 1; - lfs_file_write(&lfs, &file[1], (const void*)"f", 1) => 1; - lfs_file_write(&lfs, &file[2], (const void*)"g", 1) => 1; + lfs1_file_write(&lfs1, &file[0], (const void*)"e", 1) => 1; + lfs1_file_write(&lfs1, &file[1], (const void*)"f", 1) => 1; + lfs1_file_write(&lfs1, &file[2], (const void*)"g", 1) => 1; } - lfs_file_close(&lfs, &file[0]); - lfs_file_close(&lfs, &file[1]); - lfs_file_close(&lfs, &file[2]); + lfs1_file_close(&lfs1, &file[0]); + lfs1_file_close(&lfs1, &file[1]); + lfs1_file_close(&lfs1, &file[2]); - lfs_dir_open(&lfs, &dir[0], "/") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "/") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + info.type => LFS1_TYPE_DIR; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "e") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "g") => 0; - info.type => LFS_TYPE_REG; + info.type => LFS1_TYPE_REG; info.size => 10; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; - lfs_file_open(&lfs, &file[0], "e", LFS_O_RDONLY) => 0; - lfs_file_open(&lfs, &file[1], "g", LFS_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[0], "e", LFS1_O_RDONLY) => 0; + lfs1_file_open(&lfs1, &file[1], "g", LFS1_O_RDONLY) => 0; for (int i = 0; i < 10; i++) { - lfs_file_read(&lfs, &file[0], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[0], buffer, 1) => 1; buffer[0] => 'e'; - lfs_file_read(&lfs, &file[1], buffer, 1) => 1; + lfs1_file_read(&lfs1, &file[1], buffer, 1) => 1; buffer[0] => 'g'; } - lfs_file_close(&lfs, &file[0]); - lfs_file_close(&lfs, &file[1]); + lfs1_file_close(&lfs1, &file[0]); + lfs1_file_close(&lfs1, &file[1]); - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_move.sh b/tests/test_move.sh index 9e5abab..27e7faa 100755 --- a/tests/test_move.sh +++ b/tests/test_move.sh @@ -4,231 +4,231 @@ set -eu echo "=== Move tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "a") => 0; + lfs1_mkdir(&lfs1, "b") => 0; + lfs1_mkdir(&lfs1, "c") => 0; + lfs1_mkdir(&lfs1, "d") => 0; - lfs_mkdir(&lfs, "a/hi") => 0; - lfs_mkdir(&lfs, "a/hi/hola") => 0; - lfs_mkdir(&lfs, "a/hi/bonjour") => 0; - lfs_mkdir(&lfs, "a/hi/ohayo") => 0; + lfs1_mkdir(&lfs1, "a/hi") => 0; + lfs1_mkdir(&lfs1, "a/hi/hola") => 0; + lfs1_mkdir(&lfs1, "a/hi/bonjour") => 0; + lfs1_mkdir(&lfs1, "a/hi/ohayo") => 0; - lfs_file_open(&lfs, &file[0], "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file[0], "hola\n", 5) => 5; - lfs_file_write(&lfs, &file[0], "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file[0], "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_open(&lfs1, &file[0], "a/hello", LFS1_O_CREAT | LFS1_O_WRONLY) => 0; + lfs1_file_write(&lfs1, &file[0], "hola\n", 5) => 5; + lfs1_file_write(&lfs1, &file[0], "bonjour\n", 8) => 8; + lfs1_file_write(&lfs1, &file[0], "ohayo\n", 6) => 6; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move file ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "a/hello", "b/hello") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "a/hello", "b/hello") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "a") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "a") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hi") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "b") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_dir_open(&lfs1, &dir[0], "b") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move file corrupt source ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "b/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "b/hello", "c/hello") => 0; + lfs1_unmount(&lfs1) => 0; TEST rm -v blocks/7 tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "b") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "b") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "c") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_dir_open(&lfs1, &dir[0], "c") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move file corrupt source and dest ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "c/hello", "d/hello") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "c/hello", "d/hello") => 0; + lfs1_unmount(&lfs1) => 0; TEST rm -v blocks/8 rm -v blocks/a tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "c") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "c") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "d") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_dir_open(&lfs1, &dir[0], "d") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move dir ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "a/hi", "b/hi") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "a/hi", "b/hi") => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "a") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "a") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "b") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_dir_open(&lfs1, &dir[0], "b") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hi") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move dir corrupt source ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "b/hi", "c/hi") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "b/hi", "c/hi") => 0; + lfs1_unmount(&lfs1) => 0; TEST rm -v blocks/7 tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "b") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "b") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "c") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_dir_open(&lfs1, &dir[0], "c") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hi") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move dir corrupt source and dest ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_rename(&lfs, "c/hi", "d/hi") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_rename(&lfs1, "c/hi", "d/hi") => 0; + lfs1_unmount(&lfs1) => 0; TEST rm -v blocks/9 rm -v blocks/a tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "c") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "c") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hi") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "d") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_dir_open(&lfs1, &dir[0], "d") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Move check ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "a/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir[0], "b/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir[0], "d/hi") => LFS_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "a/hi") => LFS1_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "b/hi") => LFS1_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "d/hi") => LFS1_ERR_NOENT; - lfs_dir_open(&lfs, &dir[0], "c/hi") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_open(&lfs1, &dir[0], "c/hi") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "hola") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "bonjour") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "ohayo") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; - lfs_dir_open(&lfs, &dir[0], "a/hello") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir[0], "b/hello") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir[0], "d/hello") => LFS_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "a/hello") => LFS1_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "b/hello") => LFS1_ERR_NOENT; + lfs1_dir_open(&lfs1, &dir[0], "d/hello") => LFS1_ERR_NOENT; - lfs_file_open(&lfs, &file[0], "c/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file[0], buffer, 5) => 5; + lfs1_file_open(&lfs1, &file[0], "c/hello", LFS1_O_RDONLY) => 0; + lfs1_file_read(&lfs1, &file[0], buffer, 5) => 5; memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file[0], buffer, 8) => 8; + lfs1_file_read(&lfs1, &file[0], buffer, 8) => 8; memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file[0], buffer, 6) => 6; + lfs1_file_read(&lfs1, &file[0], buffer, 6) => 6; memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST diff --git a/tests/test_orphan.sh b/tests/test_orphan.sh index 71d6d4f..d120c10 100755 --- a/tests/test_orphan.sh +++ b/tests/test_orphan.sh @@ -4,37 +4,37 @@ set -eu echo "=== Orphan tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST echo "--- Orphan test ---" tests/test.py << TEST - 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; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "parent") => 0; + lfs1_mkdir(&lfs1, "parent/orphan") => 0; + lfs1_mkdir(&lfs1, "parent/child") => 0; + lfs1_remove(&lfs1, "parent/orphan") => 0; TEST # remove most recent file, this should be the update to the previous # linked-list entry and should orphan the child rm -v blocks/8 tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "parent/orphan", &info) => LFS1_ERR_NOENT; unsigned before = 0; - lfs_traverse(&lfs, test_count, &before) => 0; + lfs1_traverse(&lfs1, test_count, &before) => 0; test_log("before", before); - lfs_deorphan(&lfs) => 0; + lfs1_deorphan(&lfs1) => 0; - lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; + lfs1_stat(&lfs1, "parent/orphan", &info) => LFS1_ERR_NOENT; unsigned after = 0; - lfs_traverse(&lfs, test_count, &after) => 0; + lfs1_traverse(&lfs1, test_count, &after) => 0; test_log("after", after); int diff = before - after; diff => 2; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_paths.sh b/tests/test_paths.sh index 79c4e66..09ca10d 100755 --- a/tests/test_paths.sh +++ b/tests/test_paths.sh @@ -4,139 +4,139 @@ set -eu echo "=== Path tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "soda") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; - lfs_mkdir(&lfs, "soda/hotsoda") => 0; - lfs_mkdir(&lfs, "soda/warmsoda") => 0; - lfs_mkdir(&lfs, "soda/coldsoda") => 0; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "tea") => 0; + lfs1_mkdir(&lfs1, "coffee") => 0; + lfs1_mkdir(&lfs1, "soda") => 0; + lfs1_mkdir(&lfs1, "tea/hottea") => 0; + lfs1_mkdir(&lfs1, "tea/warmtea") => 0; + lfs1_mkdir(&lfs1, "tea/coldtea") => 0; + lfs1_mkdir(&lfs1, "coffee/hotcoffee") => 0; + lfs1_mkdir(&lfs1, "coffee/warmcoffee") => 0; + lfs1_mkdir(&lfs1, "coffee/coldcoffee") => 0; + lfs1_mkdir(&lfs1, "soda/hotsoda") => 0; + lfs1_mkdir(&lfs1, "soda/warmsoda") => 0; + lfs1_mkdir(&lfs1, "soda/coldsoda") => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Root path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "tea/hottea", &info) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "/tea/hottea", &info) => 0; + lfs1_stat(&lfs1, "/tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_mkdir(&lfs, "/milk1") => 0; - lfs_stat(&lfs, "/milk1", &info) => 0; + lfs1_mkdir(&lfs1, "/milk1") => 0; + lfs1_stat(&lfs1, "/milk1", &info) => 0; strcmp(info.name, "milk1") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Redundant slash path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "/tea/hottea", &info) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "/tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "//tea//hottea", &info) => 0; + lfs1_stat(&lfs1, "//tea//hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "///tea///hottea", &info) => 0; + lfs1_stat(&lfs1, "///tea///hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_mkdir(&lfs, "///milk2") => 0; - lfs_stat(&lfs, "///milk2", &info) => 0; + lfs1_mkdir(&lfs1, "///milk2") => 0; + lfs1_stat(&lfs1, "///milk2", &info) => 0; strcmp(info.name, "milk2") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Dot path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "./tea/hottea", &info) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "./tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "/./tea/hottea", &info) => 0; + lfs1_stat(&lfs1, "/./tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "/././tea/hottea", &info) => 0; + lfs1_stat(&lfs1, "/././tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; + lfs1_stat(&lfs1, "/./tea/./hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_mkdir(&lfs, "/./milk3") => 0; - lfs_stat(&lfs, "/./milk3", &info) => 0; + lfs1_mkdir(&lfs1, "/./milk3") => 0; + lfs1_stat(&lfs1, "/./milk3", &info) => 0; strcmp(info.name, "milk3") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Dot dot path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "coffee/../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; + lfs1_stat(&lfs1, "tea/coldtea/../hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; + lfs1_stat(&lfs1, "coffee/coldcoffee/../../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "coffee/../soda/../tea/hottea", &info) => 0; + lfs1_stat(&lfs1, "coffee/../soda/../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_mkdir(&lfs, "coffee/../milk4") => 0; - lfs_stat(&lfs, "coffee/../milk4", &info) => 0; + lfs1_mkdir(&lfs1, "coffee/../milk4") => 0; + lfs1_stat(&lfs1, "coffee/../milk4", &info) => 0; strcmp(info.name, "milk4") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Trailing dot path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "tea/hottea/", &info) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "tea/hottea/", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "tea/hottea/.", &info) => 0; + lfs1_stat(&lfs1, "tea/hottea/.", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; + lfs1_stat(&lfs1, "tea/hottea/./.", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_stat(&lfs, "tea/hottea/..", &info) => 0; + lfs1_stat(&lfs1, "tea/hottea/..", &info) => 0; strcmp(info.name, "tea") => 0; - lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; + lfs1_stat(&lfs1, "tea/hottea/../.", &info) => 0; strcmp(info.name, "tea") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Root dot dot path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "coffee/../../../../../../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; - lfs_mkdir(&lfs, "coffee/../../../../../../milk5") => 0; - lfs_stat(&lfs, "coffee/../../../../../../milk5", &info) => 0; + lfs1_mkdir(&lfs1, "coffee/../../../../../../milk5") => 0; + lfs1_stat(&lfs1, "coffee/../../../../../../milk5", &info) => 0; strcmp(info.name, "milk5") => 0; - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Root tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_stat(&lfs, "/", &info) => 0; - info.type => LFS_TYPE_DIR; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_stat(&lfs1, "/", &info) => 0; + info.type => LFS1_TYPE_DIR; strcmp(info.name, "/") => 0; - lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; - lfs_file_open(&lfs, &file[0], "/", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_ISDIR; - lfs_unmount(&lfs) => 0; + lfs1_mkdir(&lfs1, "/") => LFS1_ERR_EXIST; + lfs1_file_open(&lfs1, &file[0], "/", LFS1_O_WRONLY | LFS1_O_CREAT) + => LFS1_ERR_ISDIR; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Sketchy path tests ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "dirt/ground") => LFS1_ERR_NOENT; + lfs1_mkdir(&lfs1, "dirt/ground/earth") => LFS1_ERR_NOENT; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_seek.sh b/tests/test_seek.sh index aa8e643..f3234f9 100755 --- a/tests/test_seek.sh +++ b/tests/test_seek.sh @@ -8,353 +8,353 @@ LARGESIZE=132 echo "=== Seek tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; - lfs_mkdir(&lfs, "hello") => 0; + lfs1_format(&lfs1, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_mkdir(&lfs1, "hello") => 0; for (int i = 0; i < $LARGESIZE; i++) { sprintf((char*)buffer, "hello/kitty%d", i); - lfs_file_open(&lfs, &file[0], (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + lfs1_file_open(&lfs1, &file[0], (char*)buffer, + LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_O_APPEND) => 0; size = strlen("kittycatcat"); memcpy(buffer, "kittycatcat", size); for (int j = 0; j < $LARGESIZE; j++) { - lfs_file_write(&lfs, &file[0], buffer, size); + lfs1_file_write(&lfs1, &file[0], buffer, size); } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Simple dir seek ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "hello") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_soff_t pos; + lfs1_soff_t pos; int i; for (i = 0; i < $SMALLSIZE; i++) { sprintf((char*)buffer, "kitty%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - pos = lfs_dir_tell(&lfs, &dir[0]); + pos = lfs1_dir_tell(&lfs1, &dir[0]); } pos >= 0 => 1; - lfs_dir_seek(&lfs, &dir[0], pos) => 0; + lfs1_dir_seek(&lfs1, &dir[0], pos) => 0; sprintf((char*)buffer, "kitty%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - lfs_dir_rewind(&lfs, &dir[0]) => 0; + lfs1_dir_rewind(&lfs1, &dir[0]) => 0; sprintf((char*)buffer, "kitty%d", 0); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - lfs_dir_seek(&lfs, &dir[0], pos) => 0; + lfs1_dir_seek(&lfs1, &dir[0], pos) => 0; sprintf((char*)buffer, "kitty%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Large dir seek ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir[0], "hello") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_dir_open(&lfs1, &dir[0], "hello") => 0; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_soff_t pos; + lfs1_soff_t pos; int i; for (i = 0; i < $MEDIUMSIZE; i++) { sprintf((char*)buffer, "kitty%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - pos = lfs_dir_tell(&lfs, &dir[0]); + pos = lfs1_dir_tell(&lfs1, &dir[0]); } pos >= 0 => 1; - lfs_dir_seek(&lfs, &dir[0], pos) => 0; + lfs1_dir_seek(&lfs1, &dir[0], pos) => 0; sprintf((char*)buffer, "kitty%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - lfs_dir_rewind(&lfs, &dir[0]) => 0; + lfs1_dir_rewind(&lfs1, &dir[0]) => 0; sprintf((char*)buffer, "kitty%d", 0); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, ".") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, "..") => 0; - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - lfs_dir_seek(&lfs, &dir[0], pos) => 0; + lfs1_dir_seek(&lfs1, &dir[0], pos) => 0; sprintf((char*)buffer, "kitty%d", i); - lfs_dir_read(&lfs, &dir[0], &info) => 1; + lfs1_dir_read(&lfs1, &dir[0], &info) => 1; strcmp(info.name, (char*)buffer) => 0; - lfs_dir_close(&lfs, &dir[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_dir_close(&lfs1, &dir[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Simple file seek ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDONLY) => 0; - lfs_soff_t pos; + lfs1_soff_t pos; size = strlen("kittycatcat"); for (int i = 0; i < $SMALLSIZE; i++) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - pos = lfs_file_tell(&lfs, &file[0]); + pos = lfs1_file_tell(&lfs1, &file[0]); } pos >= 0 => 1; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_rewind(&lfs, &file[0]) => 0; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_rewind(&lfs1, &file[0]) => 0; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], size, LFS1_SEEK_CUR) => 3*size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_CUR) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - size = lfs_file_size(&lfs, &file[0]); - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; + size = lfs1_file_size(&lfs1, &file[0]); + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Large file seek ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDONLY) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDONLY) => 0; - lfs_soff_t pos; + lfs1_soff_t pos; size = strlen("kittycatcat"); for (int i = 0; i < $MEDIUMSIZE; i++) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - pos = lfs_file_tell(&lfs, &file[0]); + pos = lfs1_file_tell(&lfs1, &file[0]); } pos >= 0 => 1; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_rewind(&lfs, &file[0]) => 0; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_rewind(&lfs1, &file[0]) => 0; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], size, LFS_SEEK_CUR) => 3*size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], size, LFS1_SEEK_CUR) => 3*size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_CUR) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_CUR) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - size = lfs_file_size(&lfs, &file[0]); - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; + size = lfs1_file_size(&lfs1, &file[0]); + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Simple file seek and write ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0; - lfs_soff_t pos; + lfs1_soff_t pos; size = strlen("kittycatcat"); for (int i = 0; i < $SMALLSIZE; i++) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - pos = lfs_file_tell(&lfs, &file[0]); + pos = lfs1_file_tell(&lfs1, &file[0]); } pos >= 0 => 1; memcpy(buffer, "doggodogdog", size); - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; - lfs_file_rewind(&lfs, &file[0]) => 0; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_rewind(&lfs1, &file[0]) => 0; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - size = lfs_file_size(&lfs, &file[0]); - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; + size = lfs1_file_size(&lfs1, &file[0]); + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Large file seek and write ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0; - lfs_soff_t pos; + lfs1_soff_t pos; size = strlen("kittycatcat"); for (int i = 0; i < $MEDIUMSIZE; i++) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; if (i != $SMALLSIZE) { memcmp(buffer, "kittycatcat", size) => 0; } - pos = lfs_file_tell(&lfs, &file[0]); + pos = lfs1_file_tell(&lfs1, &file[0]); } pos >= 0 => 1; memcpy(buffer, "doggodogdog", size); - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; - lfs_file_rewind(&lfs, &file[0]) => 0; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_rewind(&lfs1, &file[0]) => 0; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_seek(&lfs, &file[0], pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], pos, LFS1_SEEK_SET) => pos; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "doggodogdog", size) => 0; - lfs_file_seek(&lfs, &file[0], -size, LFS_SEEK_END) >= 0 => 1; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], -size, LFS1_SEEK_END) >= 0 => 1; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - size = lfs_file_size(&lfs, &file[0]); - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; + size = lfs1_file_size(&lfs1, &file[0]); + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_CUR) => size; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Boundary seek and write ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0; size = strlen("hedgehoghog"); - const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; + const lfs1_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { - lfs_soff_t off = offsets[i]; + lfs1_soff_t off = offsets[i]; memcpy(buffer, "hedgehoghog", size); - lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; - lfs_file_write(&lfs, &file[0], buffer, size) => size; - lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], off, LFS1_SEEK_SET) => off; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], off, LFS1_SEEK_SET) => off; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "hedgehoghog", size) => 0; - lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_SET) => 0; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], 0, LFS1_SEEK_SET) => 0; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "kittycatcat", size) => 0; - lfs_file_sync(&lfs, &file[0]) => 0; + lfs1_file_sync(&lfs1, &file[0]) => 0; } - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Out-of-bounds seek ---" tests/test.py << TEST - lfs_mount(&lfs, &cfg) => 0; - lfs_file_open(&lfs, &file[0], "hello/kitty42", LFS_O_RDWR) => 0; + lfs1_mount(&lfs1, &cfg) => 0; + lfs1_file_open(&lfs1, &file[0], "hello/kitty42", LFS1_O_RDWR) => 0; size = strlen("kittycatcat"); - lfs_file_size(&lfs, &file[0]) => $LARGESIZE*size; - lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size, - LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; - lfs_file_read(&lfs, &file[0], buffer, size) => 0; + lfs1_file_size(&lfs1, &file[0]) => $LARGESIZE*size; + lfs1_file_seek(&lfs1, &file[0], ($LARGESIZE+$SMALLSIZE)*size, + LFS1_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => 0; memcpy(buffer, "porcupineee", size); - lfs_file_write(&lfs, &file[0], buffer, size) => size; + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; - lfs_file_seek(&lfs, &file[0], ($LARGESIZE+$SMALLSIZE)*size, - LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], ($LARGESIZE+$SMALLSIZE)*size, + LFS1_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "porcupineee", size) => 0; - lfs_file_seek(&lfs, &file[0], $LARGESIZE*size, - LFS_SEEK_SET) => $LARGESIZE*size; - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_seek(&lfs1, &file[0], $LARGESIZE*size, + LFS1_SEEK_SET) => $LARGESIZE*size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; - lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+$SMALLSIZE)*size), - LFS_SEEK_CUR) => LFS_ERR_INVAL; - lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size; + lfs1_file_seek(&lfs1, &file[0], -(($LARGESIZE+$SMALLSIZE)*size), + LFS1_SEEK_CUR) => LFS1_ERR_INVAL; + lfs1_file_tell(&lfs1, &file[0]) => ($LARGESIZE+1)*size; - lfs_file_seek(&lfs, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size), - LFS_SEEK_END) => LFS_ERR_INVAL; - lfs_file_tell(&lfs, &file[0]) => ($LARGESIZE+1)*size; + lfs1_file_seek(&lfs1, &file[0], -(($LARGESIZE+2*$SMALLSIZE)*size), + LFS1_SEEK_END) => LFS1_ERR_INVAL; + lfs1_file_tell(&lfs1, &file[0]) => ($LARGESIZE+1)*size; - lfs_file_close(&lfs, &file[0]) => 0; - lfs_unmount(&lfs) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; + lfs1_unmount(&lfs1) => 0; TEST echo "--- Results ---" diff --git a/tests/test_truncate.sh b/tests/test_truncate.sh index 053b2e0..1d9432a 100755 --- a/tests/test_truncate.sh +++ b/tests/test_truncate.sh @@ -8,7 +8,7 @@ LARGESIZE=8192 echo "=== Truncate tests ===" rm -rf blocks tests/test.py << TEST - lfs_format(&lfs, &cfg) => 0; + lfs1_format(&lfs1, &cfg) => 0; TEST truncate_test() { @@ -17,98 +17,98 @@ STARTSEEKS="$2" HOTSIZES="$3" COLDSIZES="$4" tests/test.py << TEST - static const lfs_off_t startsizes[] = {$STARTSIZES}; - static const lfs_off_t startseeks[] = {$STARTSEEKS}; - static const lfs_off_t hotsizes[] = {$HOTSIZES}; + static const lfs1_off_t startsizes[] = {$STARTSIZES}; + static const lfs1_off_t startseeks[] = {$STARTSEEKS}; + static const lfs1_off_t hotsizes[] = {$HOTSIZES}; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { sprintf((char*)buffer, "hairyhead%d", i); - lfs_file_open(&lfs, &file[0], (const char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; + lfs1_file_open(&lfs1, &file[0], (const char*)buffer, + LFS1_O_WRONLY | LFS1_O_CREAT | LFS1_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[0], buffer, size) => size; + for (lfs1_off_t j = 0; j < startsizes[i]; j += size) { + lfs1_file_write(&lfs1, &file[0], buffer, size) => size; } - lfs_file_size(&lfs, &file[0]) => startsizes[i]; + lfs1_file_size(&lfs1, &file[0]) => startsizes[i]; if (startseeks[i] != startsizes[i]) { - lfs_file_seek(&lfs, &file[0], - startseeks[i], LFS_SEEK_SET) => startseeks[i]; + lfs1_file_seek(&lfs1, &file[0], + startseeks[i], LFS1_SEEK_SET) => startseeks[i]; } - lfs_file_truncate(&lfs, &file[0], hotsizes[i]) => 0; - lfs_file_size(&lfs, &file[0]) => hotsizes[i]; + lfs1_file_truncate(&lfs1, &file[0], hotsizes[i]) => 0; + lfs1_file_size(&lfs1, &file[0]) => hotsizes[i]; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - static const lfs_off_t startsizes[] = {$STARTSIZES}; - static const lfs_off_t hotsizes[] = {$HOTSIZES}; - static const lfs_off_t coldsizes[] = {$COLDSIZES}; + static const lfs1_off_t startsizes[] = {$STARTSIZES}; + static const lfs1_off_t hotsizes[] = {$HOTSIZES}; + static const lfs1_off_t coldsizes[] = {$COLDSIZES}; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { sprintf((char*)buffer, "hairyhead%d", i); - lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file[0]) => hotsizes[i]; + lfs1_file_open(&lfs1, &file[0], (const char*)buffer, LFS1_O_RDWR) => 0; + lfs1_file_size(&lfs1, &file[0]) => hotsizes[i]; size = strlen("hair"); - lfs_off_t j = 0; + lfs1_off_t j = 0; for (; j < startsizes[i] && j < hotsizes[i]; j += size) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "hair", size) => 0; } for (; j < hotsizes[i]; j += size) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "\0\0\0\0", size) => 0; } - lfs_file_truncate(&lfs, &file[0], coldsizes[i]) => 0; - lfs_file_size(&lfs, &file[0]) => coldsizes[i]; + lfs1_file_truncate(&lfs1, &file[0], coldsizes[i]) => 0; + lfs1_file_size(&lfs1, &file[0]) => coldsizes[i]; - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST tests/test.py << TEST - static const lfs_off_t startsizes[] = {$STARTSIZES}; - static const lfs_off_t hotsizes[] = {$HOTSIZES}; - static const lfs_off_t coldsizes[] = {$COLDSIZES}; + static const lfs1_off_t startsizes[] = {$STARTSIZES}; + static const lfs1_off_t hotsizes[] = {$HOTSIZES}; + static const lfs1_off_t coldsizes[] = {$COLDSIZES}; - lfs_mount(&lfs, &cfg) => 0; + lfs1_mount(&lfs1, &cfg) => 0; for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { sprintf((char*)buffer, "hairyhead%d", i); - lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file[0]) => coldsizes[i]; + lfs1_file_open(&lfs1, &file[0], (const char*)buffer, LFS1_O_RDONLY) => 0; + lfs1_file_size(&lfs1, &file[0]) => coldsizes[i]; size = strlen("hair"); - lfs_off_t j = 0; + lfs1_off_t j = 0; for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; j += size) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "hair", size) => 0; } for (; j < coldsizes[i]; j += size) { - lfs_file_read(&lfs, &file[0], buffer, size) => size; + lfs1_file_read(&lfs1, &file[0], buffer, size) => size; memcmp(buffer, "\0\0\0\0", size) => 0; } - lfs_file_close(&lfs, &file[0]) => 0; + lfs1_file_close(&lfs1, &file[0]) => 0; } - lfs_unmount(&lfs) => 0; + lfs1_unmount(&lfs1) => 0; TEST }