forked from Imagelibrary/littlefs
Compare commits
40 Commits
inline-max
...
fix-enospc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea431bd6ae | ||
|
|
2d62d2f4c9 | ||
|
|
1f82c0f27f | ||
|
|
b78afe2518 | ||
|
|
798073c2a7 | ||
|
|
7db9e1663a | ||
|
|
2c4b262c35 | ||
|
|
72a4b57f4e | ||
|
|
6e7269890a | ||
|
|
d01280e649 | ||
|
|
6e52140d51 | ||
|
|
0bbb8bc88b | ||
|
|
78082336e7 | ||
|
|
8336ecd203 | ||
|
|
68d28b5114 | ||
|
|
1bc14933b7 | ||
|
|
01b6a47ea8 | ||
|
|
749a45650f | ||
|
|
11b036cc6c | ||
|
|
25ee90fdf1 | ||
|
|
a60a986c9c | ||
|
|
4dd30c1b8f | ||
|
|
5c0d332ecd | ||
|
|
cf68333a55 | ||
|
|
7873d811a0 | ||
|
|
fc2aa3350c | ||
|
|
6352185949 | ||
|
|
f2a6f45eef | ||
|
|
2752d8c486 | ||
|
|
ddbfcaa722 | ||
|
|
f53a0cc961 | ||
|
|
42910bc8e5 | ||
|
|
a3e1d12ce1 | ||
|
|
a70870c628 | ||
|
|
ceb17a0f4a | ||
|
|
a8a0905777 | ||
|
|
13d78616fe | ||
|
|
f522ed907a | ||
|
|
4f32738cd6 | ||
|
|
897b571318 |
2
.github/workflows/post-release.yml
vendored
2
.github/workflows/post-release.yml
vendored
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
post-release:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# trigger post-release in dependency repo, this indirection allows the
|
||||
# dependency repo to be updated often without affecting this repo. At
|
||||
|
||||
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# need to manually check for a couple things
|
||||
# - tests passed?
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
github.event.workflow_run.head_sha == github.sha}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{github.event.workflow_run.head_sha}}
|
||||
# need workflow access since we push branches
|
||||
@@ -30,26 +30,29 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
# try to get results from tests
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: ${{github.event.workflow_run.name}}
|
||||
run_id: ${{github.event.workflow_run.id}}
|
||||
name: sizes
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
run-id: ${{github.event.workflow_run.id}}
|
||||
pattern: '{sizes,sizes-*}'
|
||||
merge-multiple: true
|
||||
path: sizes
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: ${{github.event.workflow_run.name}}
|
||||
run_id: ${{github.event.workflow_run.id}}
|
||||
name: cov
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
run-id: ${{github.event.workflow_run.id}}
|
||||
pattern: '{cov,cov-*}'
|
||||
merge-multiple: true
|
||||
path: cov
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: ${{github.event.workflow_run.name}}
|
||||
run_id: ${{github.event.workflow_run.id}}
|
||||
name: bench
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
run-id: ${{github.event.workflow_run.id}}
|
||||
pattern: '{bench,bench-*}'
|
||||
merge-multiple: true
|
||||
path: bench
|
||||
|
||||
- name: find-version
|
||||
|
||||
22
.github/workflows/status.yml
vendored
22
.github/workflows/status.yml
vendored
@@ -11,14 +11,15 @@ defaults:
|
||||
jobs:
|
||||
# forward custom statuses
|
||||
status:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: ${{github.event.workflow_run.name}}
|
||||
run_id: ${{github.event.workflow_run.id}}
|
||||
name: status
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
run-id: ${{github.event.workflow_run.id}}
|
||||
pattern: '{status,status-*}'
|
||||
merge-multiple: true
|
||||
path: status
|
||||
- name: update-status
|
||||
continue-on-error: true
|
||||
@@ -60,19 +61,20 @@ jobs:
|
||||
|
||||
# forward custom pr-comments
|
||||
comment:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# only run on success (we don't want garbage comments!)
|
||||
if: ${{github.event.workflow_run.conclusion == 'success'}}
|
||||
|
||||
steps:
|
||||
# generated comment?
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: ${{github.event.workflow_run.name}}
|
||||
run_id: ${{github.event.workflow_run.id}}
|
||||
name: comment
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
run-id: ${{github.event.workflow_run.id}}
|
||||
pattern: '{comment,comment-*}'
|
||||
merge-multiple: true
|
||||
path: comment
|
||||
- name: update-comment
|
||||
continue-on-error: true
|
||||
|
||||
96
.github/workflows/test.yml
vendored
96
.github/workflows/test.yml
vendored
@@ -14,14 +14,14 @@ env:
|
||||
jobs:
|
||||
# run tests
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64, thumb, mips, powerpc]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -235,9 +235,9 @@ jobs:
|
||||
|
||||
# create size statuses
|
||||
- name: upload-sizes
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sizes
|
||||
name: sizes-${{matrix.arch}}
|
||||
path: sizes
|
||||
- name: status-sizes
|
||||
run: |
|
||||
@@ -273,16 +273,17 @@ jobs:
|
||||
}' | tee status/$(basename $f .csv).json
|
||||
done
|
||||
- name: upload-status-sizes
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{matrix.arch == 'x86_64'}}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: status
|
||||
name: status-sizes-${{matrix.arch}}
|
||||
path: status
|
||||
retention-days: 1
|
||||
|
||||
# create cov statuses
|
||||
- name: upload-cov
|
||||
if: ${{matrix.arch == 'x86_64'}}
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cov
|
||||
path: cov
|
||||
@@ -317,11 +318,11 @@ jobs:
|
||||
target_step: env.STEP,
|
||||
}' | tee status/$(basename $f .csv)-$s.json
|
||||
done
|
||||
- name: upload-status-sizes
|
||||
- name: upload-status-cov
|
||||
if: ${{matrix.arch == 'x86_64'}}
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: status
|
||||
name: status-cov
|
||||
path: status
|
||||
retention-days: 1
|
||||
|
||||
@@ -329,14 +330,14 @@ jobs:
|
||||
#
|
||||
# this grows exponentially, so it doesn't turn out to be that many
|
||||
test-pls:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pls: [1, 2]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -359,9 +360,9 @@ jobs:
|
||||
|
||||
# run with LFS_NO_INTRINSICS to make sure that works
|
||||
test-no-intrinsics:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -376,9 +377,9 @@ jobs:
|
||||
|
||||
# run LFS_MULTIVERSION tests
|
||||
test-multiversion:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -393,9 +394,9 @@ jobs:
|
||||
|
||||
# run tests on the older version lfs2.0
|
||||
test-lfs2_0:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -412,9 +413,9 @@ jobs:
|
||||
|
||||
# run under Valgrind to check for memory errors
|
||||
test-valgrind:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -434,9 +435,9 @@ jobs:
|
||||
# test that compilation is warning free under clang
|
||||
# run with Clang, mostly to check for Clang-specific warnings
|
||||
test-clang:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -457,9 +458,9 @@ jobs:
|
||||
#
|
||||
# note there's no real benefit to running these on multiple archs
|
||||
bench:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -491,7 +492,7 @@ jobs:
|
||||
|
||||
# create bench statuses
|
||||
- name: upload-bench
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bench
|
||||
path: bench
|
||||
@@ -525,20 +526,20 @@ jobs:
|
||||
}' | tee status/$(basename $f .csv)-$s.json
|
||||
done
|
||||
- name: upload-status-bench
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: status
|
||||
name: status-bench
|
||||
path: status
|
||||
retention-days: 1
|
||||
|
||||
# run compatibility tests using the current master as the previous version
|
||||
test-compat:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
# checkout the current pr target into lfsp
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
with:
|
||||
ref: ${{github.event.pull_request.base.ref}}
|
||||
@@ -569,10 +570,10 @@ jobs:
|
||||
|
||||
# self-host with littlefs-fuse for a fuzz-like test
|
||||
fuse:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{!endsWith(github.ref, '-prefix')}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -582,7 +583,7 @@ jobs:
|
||||
gcc --version
|
||||
python3 --version
|
||||
fusermount -V
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: littlefs-project/littlefs-fuse
|
||||
ref: v2
|
||||
@@ -619,10 +620,10 @@ jobs:
|
||||
|
||||
# test migration using littlefs-fuse
|
||||
migrate:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{!endsWith(github.ref, '-prefix')}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: install
|
||||
run: |
|
||||
# need a few things
|
||||
@@ -632,12 +633,12 @@ jobs:
|
||||
gcc --version
|
||||
python3 --version
|
||||
fusermount -V
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: littlefs-project/littlefs-fuse
|
||||
ref: v2
|
||||
path: v2
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: littlefs-project/littlefs-fuse
|
||||
ref: v1
|
||||
@@ -691,10 +692,10 @@ jobs:
|
||||
|
||||
# status related tasks that run after tests
|
||||
status:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test, bench]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
- name: install
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
@@ -704,23 +705,26 @@ jobs:
|
||||
pip3 install toml
|
||||
gcc --version
|
||||
python3 --version
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: sizes
|
||||
pattern: '{sizes,sizes-*}'
|
||||
merge-multiple: true
|
||||
path: sizes
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: cov
|
||||
pattern: '{cov,cov-*}'
|
||||
merge-multiple: true
|
||||
path: cov
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v4
|
||||
if: ${{github.event_name == 'pull_request'}}
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: bench
|
||||
pattern: '{bench,bench-*}'
|
||||
merge-multiple: true
|
||||
path: bench
|
||||
|
||||
# try to find results from tests
|
||||
@@ -862,7 +866,7 @@ jobs:
|
||||
body: $comment,
|
||||
}' | tee comment/comment.json
|
||||
- name: upload-comment
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: comment
|
||||
path: comment
|
||||
|
||||
34
README.md
34
README.md
@@ -231,11 +231,25 @@ License Identifiers that are here available: http://spdx.org/licenses/
|
||||
to use littlefs in a Rust-friendly API, reaping the benefits of Rust's memory
|
||||
safety and other guarantees.
|
||||
|
||||
- [nim-littlefs] - A Nim wrapper and API for littlefs. Includes a fuse
|
||||
implementation based on [littlefs-fuse]
|
||||
|
||||
- [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for
|
||||
use with the MirageOS library operating system project. It is interoperable
|
||||
with the reference implementation, with some caveats.
|
||||
|
||||
- [littlefs-disk-img-viewer] - A memory-efficient web application for viewing
|
||||
littlefs disk images in your web browser.
|
||||
|
||||
- [mklfs] - A command line tool built by the [Lua RTOS] guys for making
|
||||
littlefs images from a host PC. Supports Windows, Mac OS, and Linux.
|
||||
- [mklfs] - A command line tool for creating littlefs images. Used in the Lua
|
||||
RTOS ecosystem.
|
||||
|
||||
- [mklittlefs] - A command line tool for creating littlefs images. Used in the
|
||||
ESP8266 and RP2040 ecosystem.
|
||||
|
||||
- [pico-littlefs-usb] - An interface for littlefs that emulates a FAT12
|
||||
filesystem over USB. Allows mounting littlefs on a host PC without additional
|
||||
drivers.
|
||||
|
||||
- [Mbed OS] - The easiest way to get started with littlefs is to jump into Mbed
|
||||
which already has block device drivers for most forms of embedded storage.
|
||||
@@ -254,23 +268,21 @@ License Identifiers that are here available: http://spdx.org/licenses/
|
||||
for microcontroller-scale devices. Due to limitations of FAT it can't provide
|
||||
power-loss resilience, but it does allow easy interop with PCs.
|
||||
|
||||
- [chamelon] - A pure-OCaml implementation of (most of) littlefs, designed for
|
||||
use with the MirageOS library operating system project. It is interoperable
|
||||
with the reference implementation, with some caveats.
|
||||
|
||||
[BSD-3-Clause]: https://spdx.org/licenses/BSD-3-Clause.html
|
||||
[littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer
|
||||
[littlefs-fuse]: https://github.com/geky/littlefs-fuse
|
||||
[FUSE]: https://github.com/libfuse/libfuse
|
||||
[littlefs-js]: https://github.com/geky/littlefs-js
|
||||
[littlefs-js-demo]:http://littlefs.geky.net/demo.html
|
||||
[littlefs-python]: https://pypi.org/project/littlefs-python/
|
||||
[littlefs2-rust]: https://crates.io/crates/littlefs2
|
||||
[nim-littlefs]: https://github.com/Graveflo/nim-littlefs
|
||||
[chamelon]: https://github.com/yomimono/chamelon
|
||||
[littlefs-disk-img-viewer]: https://github.com/tniessen/littlefs-disk-img-viewer
|
||||
[mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src
|
||||
[Lua RTOS]: https://github.com/whitecatboard/Lua-RTOS-ESP32
|
||||
[mklittlefs]: https://github.com/earlephilhower/mklittlefs
|
||||
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb
|
||||
[Mbed OS]: https://github.com/armmbed/mbed-os
|
||||
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html
|
||||
[SPIFFS]: https://github.com/pellepl/spiffs
|
||||
[Dhara]: https://github.com/dlbeer/dhara
|
||||
[ChaN's FatFs]: http://elm-chan.org/fsw/ff/00index_e.html
|
||||
[littlefs-python]: https://pypi.org/project/littlefs-python/
|
||||
[littlefs2-rust]: https://crates.io/crates/littlefs2
|
||||
[chamelon]: https://github.com/yomimono/chamelon
|
||||
|
||||
7
SPEC.md
7
SPEC.md
@@ -441,9 +441,10 @@ Superblock fields:
|
||||
|
||||
7. **Attr max (32-bits)** - Maximum size of file attributes in bytes.
|
||||
|
||||
The superblock must always be the first entry (id 0) in a metadata pair as well
|
||||
as be the first entry written to the block. This means that the superblock
|
||||
entry can be read from a device using offsets alone.
|
||||
The superblock must always be the first entry (id 0) in the metadata pair, and
|
||||
the name tag must always be the first tag in the metadata pair. This makes it
|
||||
so that the magic string "littlefs" will always reside at offset=8 in a valid
|
||||
littlefs superblock.
|
||||
|
||||
---
|
||||
#### `0x2xx` LFS_TYPE_STRUCT
|
||||
|
||||
114
bd/lfs_emubd.c
114
bd/lfs_emubd.c
@@ -129,6 +129,8 @@ int lfs_emubd_create(const struct lfs_config *cfg,
|
||||
bd->proged = 0;
|
||||
bd->erased = 0;
|
||||
bd->power_cycles = bd->cfg->power_cycles;
|
||||
bd->ooo_block = -1;
|
||||
bd->ooo_data = NULL;
|
||||
bd->disk = NULL;
|
||||
|
||||
if (bd->cfg->disk_path) {
|
||||
@@ -195,6 +197,7 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
|
||||
free(bd->blocks);
|
||||
|
||||
// clean up other resources
|
||||
lfs_emubd_decblock(bd->ooo_data);
|
||||
if (bd->disk) {
|
||||
bd->disk->rc -= 1;
|
||||
if (bd->disk->rc == 0) {
|
||||
@@ -209,6 +212,75 @@ int lfs_emubd_destroy(const struct lfs_config *cfg) {
|
||||
}
|
||||
|
||||
|
||||
// powerloss hook
|
||||
static int lfs_emubd_powerloss(const struct lfs_config *cfg) {
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// emulate out-of-order writes?
|
||||
lfs_emubd_block_t *ooo_data = NULL;
|
||||
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
|
||||
&& bd->ooo_block != -1) {
|
||||
// since writes between syncs are allowed to be out-of-order, it
|
||||
// shouldn't hurt to restore the first write on powerloss, right?
|
||||
ooo_data = bd->blocks[bd->ooo_block];
|
||||
bd->blocks[bd->ooo_block] = lfs_emubd_incblock(bd->ooo_data);
|
||||
|
||||
// mirror to disk file?
|
||||
if (bd->disk
|
||||
&& (bd->blocks[bd->ooo_block]
|
||||
|| bd->cfg->erase_value != -1)) {
|
||||
off_t res1 = lseek(bd->disk->fd,
|
||||
(off_t)bd->ooo_block*bd->cfg->erase_size,
|
||||
SEEK_SET);
|
||||
if (res1 < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ssize_t res2 = write(bd->disk->fd,
|
||||
(bd->blocks[bd->ooo_block])
|
||||
? bd->blocks[bd->ooo_block]->data
|
||||
: bd->disk->scratch,
|
||||
bd->cfg->erase_size);
|
||||
if (res2 < 0) {
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simulate power loss
|
||||
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
|
||||
|
||||
// if we continue, undo out-of-order write emulation
|
||||
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
|
||||
&& bd->ooo_block != -1) {
|
||||
lfs_emubd_decblock(bd->blocks[bd->ooo_block]);
|
||||
bd->blocks[bd->ooo_block] = ooo_data;
|
||||
|
||||
// mirror to disk file?
|
||||
if (bd->disk
|
||||
&& (bd->blocks[bd->ooo_block]
|
||||
|| bd->cfg->erase_value != -1)) {
|
||||
off_t res1 = lseek(bd->disk->fd,
|
||||
(off_t)bd->ooo_block*bd->cfg->erase_size,
|
||||
SEEK_SET);
|
||||
if (res1 < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ssize_t res2 = write(bd->disk->fd,
|
||||
(bd->blocks[bd->ooo_block])
|
||||
? bd->blocks[bd->ooo_block]->data
|
||||
: bd->disk->scratch,
|
||||
bd->cfg->erase_size);
|
||||
if (res2 < 0) {
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// block device API
|
||||
|
||||
@@ -344,8 +416,11 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
|
||||
if (bd->power_cycles > 0) {
|
||||
bd->power_cycles -= 1;
|
||||
if (bd->power_cycles == 0) {
|
||||
// simulate power loss
|
||||
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
|
||||
int err = lfs_emubd_powerloss(cfg);
|
||||
if (err) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,10 +436,17 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
// check if erase is valid
|
||||
LFS_ASSERT(block < bd->cfg->erase_count);
|
||||
|
||||
// emulate out-of-order writes? save first write
|
||||
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO
|
||||
&& bd->ooo_block == -1) {
|
||||
bd->ooo_block = block;
|
||||
bd->ooo_data = lfs_emubd_incblock(bd->blocks[block]);
|
||||
}
|
||||
|
||||
// get the block
|
||||
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
|
||||
if (!b) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_NOMEM);
|
||||
return LFS_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@@ -430,8 +512,11 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
if (bd->power_cycles > 0) {
|
||||
bd->power_cycles -= 1;
|
||||
if (bd->power_cycles == 0) {
|
||||
// simulate power loss
|
||||
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
|
||||
int err = lfs_emubd_powerloss(cfg);
|
||||
if (err) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,17 +526,24 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
|
||||
int lfs_emubd_sync(const struct lfs_config *cfg) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_sync(%p)", (void*)cfg);
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
// do nothing
|
||||
(void)cfg;
|
||||
// emulate out-of-order writes? reset first write, writes
|
||||
// cannot be out-of-order across sync
|
||||
if (bd->cfg->powerloss_behavior == LFS_EMUBD_POWERLOSS_OOO) {
|
||||
lfs_emubd_decblock(bd->ooo_data);
|
||||
bd->ooo_block = -1;
|
||||
bd->ooo_data = NULL;
|
||||
}
|
||||
|
||||
LFS_EMUBD_TRACE("lfs_emubd_sync -> %d", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// Additional extended API for driving test features ///
|
||||
|
||||
static int lfs_emubd_rawcrc(const struct lfs_config *cfg,
|
||||
static int lfs_emubd_crc_(const struct lfs_config *cfg,
|
||||
lfs_block_t block, uint32_t *crc) {
|
||||
lfs_emubd_t *bd = cfg->context;
|
||||
|
||||
@@ -480,7 +572,7 @@ int lfs_emubd_crc(const struct lfs_config *cfg,
|
||||
lfs_block_t block, uint32_t *crc) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)",
|
||||
(void*)cfg, block, crc);
|
||||
int err = lfs_emubd_rawcrc(cfg, block, crc);
|
||||
int err = lfs_emubd_crc_(cfg, block, crc);
|
||||
LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err);
|
||||
return err;
|
||||
}
|
||||
@@ -491,7 +583,7 @@ int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc) {
|
||||
uint32_t crc_ = 0xffffffff;
|
||||
for (lfs_block_t i = 0; i < cfg->block_count; i++) {
|
||||
uint32_t i_crc;
|
||||
int err = lfs_emubd_rawcrc(cfg, i, &i_crc);
|
||||
int err = lfs_emubd_crc_(cfg, i, &i_crc);
|
||||
if (err) {
|
||||
LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err);
|
||||
return err;
|
||||
@@ -633,6 +725,8 @@ int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) {
|
||||
copy->proged = bd->proged;
|
||||
copy->erased = bd->erased;
|
||||
copy->power_cycles = bd->power_cycles;
|
||||
copy->ooo_block = bd->ooo_block;
|
||||
copy->ooo_data = lfs_emubd_incblock(bd->ooo_data);
|
||||
copy->disk = bd->disk;
|
||||
if (copy->disk) {
|
||||
copy->disk->rc += 1;
|
||||
|
||||
@@ -36,17 +36,18 @@ extern "C"
|
||||
// Not that read-noop is not allowed. Read _must_ return a consistent (but
|
||||
// may be arbitrary) value on every read.
|
||||
typedef enum lfs_emubd_badblock_behavior {
|
||||
LFS_EMUBD_BADBLOCK_PROGERROR,
|
||||
LFS_EMUBD_BADBLOCK_ERASEERROR,
|
||||
LFS_EMUBD_BADBLOCK_READERROR,
|
||||
LFS_EMUBD_BADBLOCK_PROGNOOP,
|
||||
LFS_EMUBD_BADBLOCK_ERASENOOP,
|
||||
LFS_EMUBD_BADBLOCK_PROGERROR = 0, // Error on prog
|
||||
LFS_EMUBD_BADBLOCK_ERASEERROR = 1, // Error on erase
|
||||
LFS_EMUBD_BADBLOCK_READERROR = 2, // Error on read
|
||||
LFS_EMUBD_BADBLOCK_PROGNOOP = 3, // Prog does nothing silently
|
||||
LFS_EMUBD_BADBLOCK_ERASENOOP = 4, // Erase does nothing silently
|
||||
} lfs_emubd_badblock_behavior_t;
|
||||
|
||||
// Mode determining how power-loss behaves during testing. For now this
|
||||
// only supports a noop behavior, leaving the data on-disk untouched.
|
||||
typedef enum lfs_emubd_powerloss_behavior {
|
||||
LFS_EMUBD_POWERLOSS_NOOP,
|
||||
LFS_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic
|
||||
LFS_EMUBD_POWERLOSS_OOO = 1, // Blocks are written out-of-order
|
||||
} lfs_emubd_powerloss_behavior_t;
|
||||
|
||||
// Type for measuring read/program/erase operations
|
||||
@@ -152,6 +153,8 @@ typedef struct lfs_emubd {
|
||||
lfs_emubd_io_t proged;
|
||||
lfs_emubd_io_t erased;
|
||||
lfs_emubd_powercycles_t power_cycles;
|
||||
lfs_ssize_t ooo_block;
|
||||
lfs_emubd_block_t *ooo_data;
|
||||
lfs_emubd_disk_t *disk;
|
||||
|
||||
const struct lfs_emubd_config *cfg;
|
||||
|
||||
243
lfs.c
243
lfs.c
@@ -550,9 +550,9 @@ static int lfs_dir_compact(lfs_t *lfs,
|
||||
lfs_mdir_t *source, uint16_t begin, uint16_t end);
|
||||
static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
|
||||
const void *buffer, lfs_size_t size);
|
||||
static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
||||
static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
|
||||
const void *buffer, lfs_size_t size);
|
||||
static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file);
|
||||
static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file);
|
||||
static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
|
||||
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
@@ -574,22 +574,22 @@ static int lfs1_traverse(lfs_t *lfs,
|
||||
int (*cb)(void*, lfs_block_t), void *data);
|
||||
#endif
|
||||
|
||||
static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir);
|
||||
static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file,
|
||||
void *buffer, lfs_size_t size);
|
||||
static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
|
||||
static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
|
||||
void *buffer, lfs_size_t size);
|
||||
static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file);
|
||||
static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file);
|
||||
static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file);
|
||||
static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs);
|
||||
static int lfs_fs_rawtraverse(lfs_t *lfs,
|
||||
static lfs_ssize_t lfs_fs_size_(lfs_t *lfs);
|
||||
static int lfs_fs_traverse_(lfs_t *lfs,
|
||||
int (*cb)(void *data, lfs_block_t block), void *data,
|
||||
bool includeorphans);
|
||||
|
||||
static int lfs_deinit(lfs_t *lfs);
|
||||
static int lfs_rawunmount(lfs_t *lfs);
|
||||
static int lfs_unmount_(lfs_t *lfs);
|
||||
|
||||
|
||||
/// Block allocator ///
|
||||
@@ -639,7 +639,7 @@ static int lfs_alloc_scan(lfs_t *lfs) {
|
||||
|
||||
// find mask of free blocks from tree
|
||||
memset(lfs->lookahead.buffer, 0, lfs->cfg->lookahead_size);
|
||||
int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true);
|
||||
int err = lfs_fs_traverse_(lfs, lfs_alloc_lookahead, lfs, true);
|
||||
if (err) {
|
||||
lfs_alloc_drop(lfs);
|
||||
return err;
|
||||
@@ -688,7 +688,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
|
||||
if (lfs->lookahead.ckpoint <= 0) {
|
||||
LFS_ERROR("No more free space 0x%"PRIx32,
|
||||
(lfs->lookahead.start + lfs->lookahead.next)
|
||||
% lfs->cfg->block_count);
|
||||
% lfs->block_count);
|
||||
return LFS_ERR_NOSPC;
|
||||
}
|
||||
|
||||
@@ -710,11 +710,14 @@ static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir,
|
||||
lfs_tag_t ntag = dir->etag;
|
||||
lfs_stag_t gdiff = 0;
|
||||
|
||||
// synthetic moves
|
||||
if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) &&
|
||||
lfs_tag_id(gmask) != 0 &&
|
||||
lfs_tag_id(lfs->gdisk.tag) <= lfs_tag_id(gtag)) {
|
||||
// synthetic moves
|
||||
gdiff -= LFS_MKTAG(0, 1, 0);
|
||||
lfs_tag_id(gmask) != 0) {
|
||||
if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(gtag)) {
|
||||
return LFS_ERR_NOENT;
|
||||
} else if (lfs_tag_id(lfs->gdisk.tag) < lfs_tag_id(gtag)) {
|
||||
gdiff -= LFS_MKTAG(0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// iterate over dir block backwards (for faster lookups)
|
||||
@@ -2125,13 +2128,14 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
// And we cap at half a block to avoid degenerate cases with
|
||||
// nearly-full metadata blocks.
|
||||
//
|
||||
lfs_size_t metadata_max = (lfs->cfg->metadata_max)
|
||||
? lfs->cfg->metadata_max
|
||||
: lfs->cfg->block_size;
|
||||
if (end - split < 0xff
|
||||
&& size <= lfs_min(
|
||||
lfs->cfg->block_size - 40,
|
||||
metadata_max - 40,
|
||||
lfs_alignup(
|
||||
(lfs->cfg->metadata_max
|
||||
? lfs->cfg->metadata_max
|
||||
: lfs->cfg->block_size)/2,
|
||||
metadata_max/2,
|
||||
lfs->cfg->prog_size))) {
|
||||
break;
|
||||
}
|
||||
@@ -2166,7 +2170,7 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
&& lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) {
|
||||
// oh no! we're writing too much to the superblock,
|
||||
// should we expand?
|
||||
lfs_ssize_t size = lfs_fs_rawsize(lfs);
|
||||
lfs_ssize_t size = lfs_fs_size_(lfs);
|
||||
if (size < 0) {
|
||||
return size;
|
||||
}
|
||||
@@ -2188,7 +2192,8 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
// we can do, we'll error later if we've become frozen
|
||||
LFS_WARN("Unable to expand superblock");
|
||||
} else {
|
||||
end = begin;
|
||||
// duplicate the superblock entry into the new superblock
|
||||
end = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2355,7 +2360,9 @@ fixmlist:;
|
||||
|
||||
while (d->id >= d->m.count && d->m.split) {
|
||||
// we split and id is on tail now
|
||||
d->id -= d->m.count;
|
||||
if (lfs_pair_cmp(d->m.tail, lfs->root) != 0) {
|
||||
d->id -= d->m.count;
|
||||
}
|
||||
int err = lfs_dir_fetch(lfs, &d->m, d->m.tail);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -2586,7 +2593,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
|
||||
/// Top level directory operations ///
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
|
||||
static int lfs_mkdir_(lfs_t *lfs, const char *path) {
|
||||
// deorphan if we haven't yet, needed at most once after poweron
|
||||
int err = lfs_fs_forceconsistency(lfs);
|
||||
if (err) {
|
||||
@@ -2682,7 +2689,7 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
|
||||
static int lfs_dir_open_(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
|
||||
lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL);
|
||||
if (tag < 0) {
|
||||
return tag;
|
||||
@@ -2726,14 +2733,14 @@ static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_rawclose(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
static int lfs_dir_close_(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
// remove from list of mdirs
|
||||
lfs_mlist_remove(lfs, (struct lfs_mlist *)dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
|
||||
static int lfs_dir_read_(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
// special offset for '.' and '..'
|
||||
@@ -2778,9 +2785,9 @@ static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
|
||||
static int lfs_dir_seek_(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
|
||||
// simply walk from head dir
|
||||
int err = lfs_dir_rawrewind(lfs, dir);
|
||||
int err = lfs_dir_rewind_(lfs, dir);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -2815,12 +2822,12 @@ static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lfs_soff_t lfs_dir_rawtell(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
static lfs_soff_t lfs_dir_tell_(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
(void)lfs;
|
||||
return dir->pos;
|
||||
}
|
||||
|
||||
static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
static int lfs_dir_rewind_(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
// reload the head dir
|
||||
int err = lfs_dir_fetch(lfs, &dir->m, dir->head);
|
||||
if (err) {
|
||||
@@ -3026,7 +3033,7 @@ static int lfs_ctz_traverse(lfs_t *lfs,
|
||||
|
||||
|
||||
/// Top level file operations ///
|
||||
static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
||||
static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file,
|
||||
const char *path, int flags,
|
||||
const struct lfs_file_config *cfg) {
|
||||
#ifndef LFS_READONLY
|
||||
@@ -3188,22 +3195,22 @@ cleanup:
|
||||
#ifndef LFS_READONLY
|
||||
file->flags |= LFS_F_ERRED;
|
||||
#endif
|
||||
lfs_file_rawclose(lfs, file);
|
||||
lfs_file_close_(lfs, file);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef LFS_NO_MALLOC
|
||||
static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file,
|
||||
static int lfs_file_open_(lfs_t *lfs, lfs_file_t *file,
|
||||
const char *path, int flags) {
|
||||
static const struct lfs_file_config defaults = {0};
|
||||
int err = lfs_file_rawopencfg(lfs, file, path, flags, &defaults);
|
||||
int err = lfs_file_opencfg_(lfs, file, path, flags, &defaults);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) {
|
||||
static int lfs_file_close_(lfs_t *lfs, lfs_file_t *file) {
|
||||
#ifndef LFS_READONLY
|
||||
int err = lfs_file_rawsync(lfs, file);
|
||||
int err = lfs_file_sync_(lfs, file);
|
||||
#else
|
||||
int err = 0;
|
||||
#endif
|
||||
@@ -3386,7 +3393,7 @@ relocate:
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
||||
static int lfs_file_sync_(lfs_t *lfs, lfs_file_t *file) {
|
||||
if (file->flags & LFS_F_ERRED) {
|
||||
// it's not safe to do anything if our file errored
|
||||
return 0;
|
||||
@@ -3401,6 +3408,15 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
||||
|
||||
if ((file->flags & LFS_F_DIRTY) &&
|
||||
!lfs_pair_isnull(file->m.pair)) {
|
||||
// before we commit metadata, we need sync the disk to make sure
|
||||
// data writes don't complete after metadata writes
|
||||
if (!(file->flags & LFS_F_INLINE)) {
|
||||
err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// update dir entry
|
||||
uint16_t type;
|
||||
const void *buffer;
|
||||
@@ -3499,7 +3515,7 @@ static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file,
|
||||
return size;
|
||||
}
|
||||
|
||||
static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
|
||||
static lfs_ssize_t lfs_file_read_(lfs_t *lfs, lfs_file_t *file,
|
||||
void *buffer, lfs_size_t size) {
|
||||
LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY);
|
||||
|
||||
@@ -3602,7 +3618,7 @@ relocate:
|
||||
return size;
|
||||
}
|
||||
|
||||
static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
||||
static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
|
||||
const void *buffer, lfs_size_t size) {
|
||||
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
|
||||
|
||||
@@ -3646,7 +3662,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
||||
}
|
||||
#endif
|
||||
|
||||
static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
||||
static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file,
|
||||
lfs_soff_t off, int whence) {
|
||||
// find new pos
|
||||
lfs_off_t npos = file->pos;
|
||||
@@ -3659,7 +3675,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
||||
npos = file->pos + off;
|
||||
}
|
||||
} else if (whence == LFS_SEEK_END) {
|
||||
lfs_soff_t res = lfs_file_rawsize(lfs, file) + off;
|
||||
lfs_soff_t res = lfs_file_size_(lfs, file) + off;
|
||||
if (res < 0) {
|
||||
return LFS_ERR_INVAL;
|
||||
} else {
|
||||
@@ -3710,7 +3726,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
static int lfs_file_truncate_(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
|
||||
|
||||
if (size > LFS_FILE_MAX) {
|
||||
@@ -3718,12 +3734,12 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
}
|
||||
|
||||
lfs_off_t pos = file->pos;
|
||||
lfs_off_t oldsize = lfs_file_rawsize(lfs, file);
|
||||
lfs_off_t oldsize = lfs_file_size_(lfs, file);
|
||||
if (size < oldsize) {
|
||||
// revert to inline file?
|
||||
if (size <= lfs->inline_max) {
|
||||
// flush+seek to head
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
|
||||
lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET);
|
||||
if (res < 0) {
|
||||
return (int)res;
|
||||
}
|
||||
@@ -3768,14 +3784,14 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
}
|
||||
} else if (size > oldsize) {
|
||||
// flush+seek if not already at end
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
|
||||
lfs_soff_t res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_END);
|
||||
if (res < 0) {
|
||||
return (int)res;
|
||||
}
|
||||
|
||||
// fill with zeros
|
||||
while (file->pos < size) {
|
||||
res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1);
|
||||
res = lfs_file_write_(lfs, file, &(uint8_t){0}, 1);
|
||||
if (res < 0) {
|
||||
return (int)res;
|
||||
}
|
||||
@@ -3783,7 +3799,7 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
}
|
||||
|
||||
// restore pos
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, pos, LFS_SEEK_SET);
|
||||
lfs_soff_t res = lfs_file_seek_(lfs, file, pos, LFS_SEEK_SET);
|
||||
if (res < 0) {
|
||||
return (int)res;
|
||||
}
|
||||
@@ -3792,13 +3808,13 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static lfs_soff_t lfs_file_rawtell(lfs_t *lfs, lfs_file_t *file) {
|
||||
static lfs_soff_t lfs_file_tell_(lfs_t *lfs, lfs_file_t *file) {
|
||||
(void)lfs;
|
||||
return file->pos;
|
||||
}
|
||||
|
||||
static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) {
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
|
||||
static 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 (int)res;
|
||||
}
|
||||
@@ -3806,7 +3822,7 @@ static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) {
|
||||
static lfs_soff_t lfs_file_size_(lfs_t *lfs, lfs_file_t *file) {
|
||||
(void)lfs;
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
@@ -3820,7 +3836,7 @@ static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) {
|
||||
|
||||
|
||||
/// General fs operations ///
|
||||
static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) {
|
||||
static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) {
|
||||
lfs_mdir_t cwd;
|
||||
lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
|
||||
if (tag < 0) {
|
||||
@@ -3831,7 +3847,7 @@ static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) {
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_rawremove(lfs_t *lfs, const char *path) {
|
||||
static int lfs_remove_(lfs_t *lfs, const char *path) {
|
||||
// deorphan if we haven't yet, needed at most once after poweron
|
||||
int err = lfs_fs_forceconsistency(lfs);
|
||||
if (err) {
|
||||
@@ -3910,7 +3926,7 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) {
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
// deorphan if we haven't yet, needed at most once after poweron
|
||||
int err = lfs_fs_forceconsistency(lfs);
|
||||
if (err) {
|
||||
@@ -3953,7 +3969,9 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
newoldid += 1;
|
||||
}
|
||||
} else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) {
|
||||
return LFS_ERR_ISDIR;
|
||||
return (lfs_tag_type3(prevtag) == LFS_TYPE_DIR)
|
||||
? LFS_ERR_ISDIR
|
||||
: LFS_ERR_NOTDIR;
|
||||
} else if (samepair && newid == newoldid) {
|
||||
// we're renaming to ourselves??
|
||||
return 0;
|
||||
@@ -4045,7 +4063,7 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static lfs_ssize_t lfs_rawgetattr(lfs_t *lfs, const char *path,
|
||||
static lfs_ssize_t lfs_getattr_(lfs_t *lfs, const char *path,
|
||||
uint8_t type, void *buffer, lfs_size_t size) {
|
||||
lfs_mdir_t cwd;
|
||||
lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL);
|
||||
@@ -4103,7 +4121,7 @@ static int lfs_commitattr(lfs_t *lfs, const char *path,
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_rawsetattr(lfs_t *lfs, const char *path,
|
||||
static int lfs_setattr_(lfs_t *lfs, const char *path,
|
||||
uint8_t type, const void *buffer, lfs_size_t size) {
|
||||
if (size > lfs->attr_max) {
|
||||
return LFS_ERR_NOSPC;
|
||||
@@ -4114,7 +4132,7 @@ static int lfs_rawsetattr(lfs_t *lfs, const char *path,
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) {
|
||||
static int lfs_removeattr_(lfs_t *lfs, const char *path, uint8_t type) {
|
||||
return lfs_commitattr(lfs, path, type, NULL, 0x3ff);
|
||||
}
|
||||
#endif
|
||||
@@ -4192,6 +4210,15 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1
|
||||
|| lfs->cfg->compact_thresh <= lfs->cfg->block_size);
|
||||
|
||||
// check that metadata_max is a multiple of read_size and prog_size,
|
||||
// and a factor of the block_size
|
||||
LFS_ASSERT(!lfs->cfg->metadata_max
|
||||
|| lfs->cfg->metadata_max % lfs->cfg->read_size == 0);
|
||||
LFS_ASSERT(!lfs->cfg->metadata_max
|
||||
|| lfs->cfg->metadata_max % lfs->cfg->prog_size == 0);
|
||||
LFS_ASSERT(!lfs->cfg->metadata_max
|
||||
|| lfs->cfg->block_size % lfs->cfg->metadata_max == 0);
|
||||
|
||||
// setup read cache
|
||||
if (lfs->cfg->read_buffer) {
|
||||
lfs->rcache.buffer = lfs->cfg->read_buffer;
|
||||
@@ -4312,7 +4339,7 @@ static int lfs_deinit(lfs_t *lfs) {
|
||||
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
static int lfs_format_(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
int err = 0;
|
||||
{
|
||||
err = lfs_init(lfs, cfg);
|
||||
@@ -4379,7 +4406,7 @@ cleanup:
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
int err = lfs_init(lfs, cfg);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -4452,6 +4479,7 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
// found older minor version? set an in-device only bit in the
|
||||
// gstate so we know we need to rewrite the superblock before
|
||||
// the first write
|
||||
bool needssuperblock = false;
|
||||
if (minor_version < lfs_fs_disk_version_minor(lfs)) {
|
||||
LFS_DEBUG("Found older minor version "
|
||||
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
|
||||
@@ -4459,10 +4487,11 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
minor_version,
|
||||
lfs_fs_disk_version_major(lfs),
|
||||
lfs_fs_disk_version_minor(lfs));
|
||||
// note this bit is reserved on disk, so fetching more gstate
|
||||
// will not interfere here
|
||||
lfs_fs_prepsuperblock(lfs, true);
|
||||
needssuperblock = true;
|
||||
}
|
||||
// note this bit is reserved on disk, so fetching more gstate
|
||||
// will not interfere here
|
||||
lfs_fs_prepsuperblock(lfs, needssuperblock);
|
||||
|
||||
// check superblock configuration
|
||||
if (superblock.name_max) {
|
||||
@@ -4545,17 +4574,17 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
lfs_rawunmount(lfs);
|
||||
lfs_unmount_(lfs);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lfs_rawunmount(lfs_t *lfs) {
|
||||
static int lfs_unmount_(lfs_t *lfs) {
|
||||
return lfs_deinit(lfs);
|
||||
}
|
||||
|
||||
|
||||
/// Filesystem filesystem operations ///
|
||||
static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
|
||||
static int lfs_fs_stat_(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
|
||||
// if the superblock is up-to-date, we must be on the most recent
|
||||
// minor version of littlefs
|
||||
if (!lfs_gstate_needssuperblock(&lfs->gstate)) {
|
||||
@@ -4595,7 +4624,7 @@ static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_fs_rawtraverse(lfs_t *lfs,
|
||||
int lfs_fs_traverse_(lfs_t *lfs,
|
||||
int (*cb)(void *data, lfs_block_t block), void *data,
|
||||
bool includeorphans) {
|
||||
// iterate over metadata pairs
|
||||
@@ -5060,7 +5089,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_fs_rawmkconsistent(lfs_t *lfs) {
|
||||
static int lfs_fs_mkconsistent_(lfs_t *lfs) {
|
||||
// lfs_fs_forceconsistency does most of the work here
|
||||
int err = lfs_fs_forceconsistency(lfs);
|
||||
if (err) {
|
||||
@@ -5096,9 +5125,9 @@ static int lfs_fs_size_count(void *p, lfs_block_t block) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) {
|
||||
static lfs_ssize_t lfs_fs_size_(lfs_t *lfs) {
|
||||
lfs_size_t size = 0;
|
||||
int err = lfs_fs_rawtraverse(lfs, lfs_fs_size_count, &size, false);
|
||||
int err = lfs_fs_traverse_(lfs, lfs_fs_size_count, &size, false);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -5108,7 +5137,7 @@ static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) {
|
||||
|
||||
// explicit garbage collection
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_fs_rawgc(lfs_t *lfs) {
|
||||
static int lfs_fs_gc_(lfs_t *lfs) {
|
||||
// force consistency, even if we're not necessarily going to write,
|
||||
// because this function is supposed to take care of janitorial work
|
||||
// isn't it?
|
||||
@@ -5158,7 +5187,7 @@ static int lfs_fs_rawgc(lfs_t *lfs) {
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_fs_rawgrow(lfs_t *lfs, lfs_size_t block_count) {
|
||||
static int lfs_fs_grow_(lfs_t *lfs, lfs_size_t block_count) {
|
||||
// shrinking is not supported
|
||||
LFS_ASSERT(block_count >= lfs->block_count);
|
||||
|
||||
@@ -5617,7 +5646,7 @@ static int lfs1_unmount(lfs_t *lfs) {
|
||||
}
|
||||
|
||||
/// v1 migration ///
|
||||
static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
static int lfs_migrate_(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
struct lfs1 lfs1;
|
||||
|
||||
// Indeterminate filesystem size not allowed for migration.
|
||||
@@ -5884,7 +5913,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
|
||||
cfg->name_max, cfg->file_max, cfg->attr_max);
|
||||
|
||||
err = lfs_rawformat(lfs, cfg);
|
||||
err = lfs_format_(lfs, cfg);
|
||||
|
||||
LFS_TRACE("lfs_format -> %d", err);
|
||||
LFS_UNLOCK(cfg);
|
||||
@@ -5914,7 +5943,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
|
||||
cfg->name_max, cfg->file_max, cfg->attr_max);
|
||||
|
||||
err = lfs_rawmount(lfs, cfg);
|
||||
err = lfs_mount_(lfs, cfg);
|
||||
|
||||
LFS_TRACE("lfs_mount -> %d", err);
|
||||
LFS_UNLOCK(cfg);
|
||||
@@ -5928,7 +5957,7 @@ int lfs_unmount(lfs_t *lfs) {
|
||||
}
|
||||
LFS_TRACE("lfs_unmount(%p)", (void*)lfs);
|
||||
|
||||
err = lfs_rawunmount(lfs);
|
||||
err = lfs_unmount_(lfs);
|
||||
|
||||
LFS_TRACE("lfs_unmount -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -5943,7 +5972,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
||||
}
|
||||
LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path);
|
||||
|
||||
err = lfs_rawremove(lfs, path);
|
||||
err = lfs_remove_(lfs, path);
|
||||
|
||||
LFS_TRACE("lfs_remove -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -5959,7 +5988,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
}
|
||||
LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath);
|
||||
|
||||
err = lfs_rawrename(lfs, oldpath, newpath);
|
||||
err = lfs_rename_(lfs, oldpath, newpath);
|
||||
|
||||
LFS_TRACE("lfs_rename -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -5974,7 +6003,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
|
||||
}
|
||||
LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info);
|
||||
|
||||
err = lfs_rawstat(lfs, path, info);
|
||||
err = lfs_stat_(lfs, path, info);
|
||||
|
||||
LFS_TRACE("lfs_stat -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -5990,7 +6019,7 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
|
||||
LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")",
|
||||
(void*)lfs, path, type, buffer, size);
|
||||
|
||||
lfs_ssize_t res = lfs_rawgetattr(lfs, path, type, buffer, size);
|
||||
lfs_ssize_t res = lfs_getattr_(lfs, path, type, buffer, size);
|
||||
|
||||
LFS_TRACE("lfs_getattr -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6007,7 +6036,7 @@ int lfs_setattr(lfs_t *lfs, const char *path,
|
||||
LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")",
|
||||
(void*)lfs, path, type, buffer, size);
|
||||
|
||||
err = lfs_rawsetattr(lfs, path, type, buffer, size);
|
||||
err = lfs_setattr_(lfs, path, type, buffer, size);
|
||||
|
||||
LFS_TRACE("lfs_setattr -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6023,7 +6052,7 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
|
||||
}
|
||||
LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type);
|
||||
|
||||
err = lfs_rawremoveattr(lfs, path, type);
|
||||
err = lfs_removeattr_(lfs, path, type);
|
||||
|
||||
LFS_TRACE("lfs_removeattr -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6041,7 +6070,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) {
|
||||
(void*)lfs, (void*)file, path, flags);
|
||||
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
err = lfs_file_rawopen(lfs, file, path, flags);
|
||||
err = lfs_file_open_(lfs, file, path, flags);
|
||||
|
||||
LFS_TRACE("lfs_file_open -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6062,7 +6091,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
||||
(void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count);
|
||||
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
err = lfs_file_rawopencfg(lfs, file, path, flags, cfg);
|
||||
err = lfs_file_opencfg_(lfs, file, path, flags, cfg);
|
||||
|
||||
LFS_TRACE("lfs_file_opencfg -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6077,7 +6106,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
|
||||
LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
err = lfs_file_rawclose(lfs, file);
|
||||
err = lfs_file_close_(lfs, file);
|
||||
|
||||
LFS_TRACE("lfs_file_close -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6093,7 +6122,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
||||
LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
err = lfs_file_rawsync(lfs, file);
|
||||
err = lfs_file_sync_(lfs, file);
|
||||
|
||||
LFS_TRACE("lfs_file_sync -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6111,7 +6140,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
|
||||
(void*)lfs, (void*)file, buffer, size);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size);
|
||||
lfs_ssize_t res = lfs_file_read_(lfs, file, buffer, size);
|
||||
|
||||
LFS_TRACE("lfs_file_read -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6129,7 +6158,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
|
||||
(void*)lfs, (void*)file, buffer, size);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size);
|
||||
lfs_ssize_t res = lfs_file_write_(lfs, file, buffer, size);
|
||||
|
||||
LFS_TRACE("lfs_file_write -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6147,7 +6176,7 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
|
||||
(void*)lfs, (void*)file, off, whence);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence);
|
||||
lfs_soff_t res = lfs_file_seek_(lfs, file, off, whence);
|
||||
|
||||
LFS_TRACE("lfs_file_seek -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6164,7 +6193,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
(void*)lfs, (void*)file, size);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
err = lfs_file_rawtruncate(lfs, file, size);
|
||||
err = lfs_file_truncate_(lfs, file, size);
|
||||
|
||||
LFS_TRACE("lfs_file_truncate -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6180,7 +6209,7 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) {
|
||||
LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
lfs_soff_t res = lfs_file_rawtell(lfs, file);
|
||||
lfs_soff_t res = lfs_file_tell_(lfs, file);
|
||||
|
||||
LFS_TRACE("lfs_file_tell -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6194,7 +6223,7 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) {
|
||||
}
|
||||
LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file);
|
||||
|
||||
err = lfs_file_rawrewind(lfs, file);
|
||||
err = lfs_file_rewind_(lfs, file);
|
||||
|
||||
LFS_TRACE("lfs_file_rewind -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6209,7 +6238,7 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
|
||||
LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file);
|
||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||
|
||||
lfs_soff_t res = lfs_file_rawsize(lfs, file);
|
||||
lfs_soff_t res = lfs_file_size_(lfs, file);
|
||||
|
||||
LFS_TRACE("lfs_file_size -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6224,7 +6253,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
|
||||
}
|
||||
LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path);
|
||||
|
||||
err = lfs_rawmkdir(lfs, path);
|
||||
err = lfs_mkdir_(lfs, path);
|
||||
|
||||
LFS_TRACE("lfs_mkdir -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6240,7 +6269,7 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
|
||||
LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path);
|
||||
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)dir));
|
||||
|
||||
err = lfs_dir_rawopen(lfs, dir, path);
|
||||
err = lfs_dir_open_(lfs, dir, path);
|
||||
|
||||
LFS_TRACE("lfs_dir_open -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6254,7 +6283,7 @@ int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
}
|
||||
LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir);
|
||||
|
||||
err = lfs_dir_rawclose(lfs, dir);
|
||||
err = lfs_dir_close_(lfs, dir);
|
||||
|
||||
LFS_TRACE("lfs_dir_close -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6269,7 +6298,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
|
||||
LFS_TRACE("lfs_dir_read(%p, %p, %p)",
|
||||
(void*)lfs, (void*)dir, (void*)info);
|
||||
|
||||
err = lfs_dir_rawread(lfs, dir, info);
|
||||
err = lfs_dir_read_(lfs, dir, info);
|
||||
|
||||
LFS_TRACE("lfs_dir_read -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6284,7 +6313,7 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
|
||||
LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")",
|
||||
(void*)lfs, (void*)dir, off);
|
||||
|
||||
err = lfs_dir_rawseek(lfs, dir, off);
|
||||
err = lfs_dir_seek_(lfs, dir, off);
|
||||
|
||||
LFS_TRACE("lfs_dir_seek -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6298,7 +6327,7 @@ lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
}
|
||||
LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir);
|
||||
|
||||
lfs_soff_t res = lfs_dir_rawtell(lfs, dir);
|
||||
lfs_soff_t res = lfs_dir_tell_(lfs, dir);
|
||||
|
||||
LFS_TRACE("lfs_dir_tell -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6312,7 +6341,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
}
|
||||
LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir);
|
||||
|
||||
err = lfs_dir_rawrewind(lfs, dir);
|
||||
err = lfs_dir_rewind_(lfs, dir);
|
||||
|
||||
LFS_TRACE("lfs_dir_rewind -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6326,7 +6355,7 @@ int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
|
||||
}
|
||||
LFS_TRACE("lfs_fs_stat(%p, %p)", (void*)lfs, (void*)fsinfo);
|
||||
|
||||
err = lfs_fs_rawstat(lfs, fsinfo);
|
||||
err = lfs_fs_stat_(lfs, fsinfo);
|
||||
|
||||
LFS_TRACE("lfs_fs_stat -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6340,7 +6369,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs) {
|
||||
}
|
||||
LFS_TRACE("lfs_fs_size(%p)", (void*)lfs);
|
||||
|
||||
lfs_ssize_t res = lfs_fs_rawsize(lfs);
|
||||
lfs_ssize_t res = lfs_fs_size_(lfs);
|
||||
|
||||
LFS_TRACE("lfs_fs_size -> %"PRId32, res);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6355,7 +6384,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
|
||||
LFS_TRACE("lfs_fs_traverse(%p, %p, %p)",
|
||||
(void*)lfs, (void*)(uintptr_t)cb, data);
|
||||
|
||||
err = lfs_fs_rawtraverse(lfs, cb, data, true);
|
||||
err = lfs_fs_traverse_(lfs, cb, data, true);
|
||||
|
||||
LFS_TRACE("lfs_fs_traverse -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6370,7 +6399,7 @@ int lfs_fs_mkconsistent(lfs_t *lfs) {
|
||||
}
|
||||
LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
|
||||
|
||||
err = lfs_fs_rawmkconsistent(lfs);
|
||||
err = lfs_fs_mkconsistent_(lfs);
|
||||
|
||||
LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6386,7 +6415,7 @@ int lfs_fs_gc(lfs_t *lfs) {
|
||||
}
|
||||
LFS_TRACE("lfs_fs_gc(%p)", (void*)lfs);
|
||||
|
||||
err = lfs_fs_rawgc(lfs);
|
||||
err = lfs_fs_gc_(lfs);
|
||||
|
||||
LFS_TRACE("lfs_fs_gc -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6402,7 +6431,7 @@ int lfs_fs_grow(lfs_t *lfs, lfs_size_t block_count) {
|
||||
}
|
||||
LFS_TRACE("lfs_fs_grow(%p, %"PRIu32")", (void*)lfs, block_count);
|
||||
|
||||
err = lfs_fs_rawgrow(lfs, block_count);
|
||||
err = lfs_fs_grow_(lfs, block_count);
|
||||
|
||||
LFS_TRACE("lfs_fs_grow -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
@@ -6433,7 +6462,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer,
|
||||
cfg->name_max, cfg->file_max, cfg->attr_max);
|
||||
|
||||
err = lfs_rawmigrate(lfs, cfg);
|
||||
err = lfs_migrate_(lfs, cfg);
|
||||
|
||||
LFS_TRACE("lfs_migrate -> %d", err);
|
||||
LFS_UNLOCK(cfg);
|
||||
|
||||
18
lfs.h
18
lfs.h
@@ -21,7 +21,7 @@ extern "C"
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS_VERSION 0x00020008
|
||||
#define LFS_VERSION 0x00020009
|
||||
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
|
||||
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
|
||||
|
||||
@@ -59,7 +59,8 @@ typedef uint32_t lfs_block_t;
|
||||
#endif
|
||||
|
||||
// Maximum size of custom attributes in bytes, may be redefined, but there is
|
||||
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
|
||||
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored
|
||||
// in superblock and must be respected by other littlefs drivers.
|
||||
#ifndef LFS_ATTR_MAX
|
||||
#define LFS_ATTR_MAX 1022
|
||||
#endif
|
||||
@@ -203,7 +204,8 @@ struct lfs_config {
|
||||
// program sizes.
|
||||
lfs_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device.
|
||||
// Number of erasable blocks on the device. Defaults to block_count stored
|
||||
// on disk when zero.
|
||||
lfs_size_t block_count;
|
||||
|
||||
// Number of erase cycles before littlefs evicts metadata logs and moves
|
||||
@@ -252,18 +254,18 @@ struct lfs_config {
|
||||
|
||||
// Optional upper limit on length of file names in bytes. No downside for
|
||||
// larger names except the size of the info struct which is controlled by
|
||||
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
|
||||
// superblock and must be respected by other littlefs drivers.
|
||||
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on
|
||||
// disk when zero.
|
||||
lfs_size_t name_max;
|
||||
|
||||
// Optional upper limit on files in bytes. No downside for larger files
|
||||
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
|
||||
// in superblock and must be respected by other littlefs drivers.
|
||||
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored
|
||||
// on disk when zero.
|
||||
lfs_size_t file_max;
|
||||
|
||||
// Optional upper limit on custom attributes in bytes. No downside for
|
||||
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
||||
// LFS_ATTR_MAX when zero.
|
||||
// LFS_ATTR_MAX or attr_max stored on disk when zero.
|
||||
lfs_size_t attr_max;
|
||||
|
||||
// Optional upper limit on total space given to metadata pairs in bytes. On
|
||||
|
||||
@@ -1322,6 +1322,7 @@ void perm_run(
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
.compact_thresh = COMPACT_THRESH,
|
||||
.metadata_max = METADATA_MAX,
|
||||
.inline_max = INLINE_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -96,12 +96,13 @@ intmax_t bench_define(size_t define);
|
||||
#define CACHE_SIZE_i 6
|
||||
#define LOOKAHEAD_SIZE_i 7
|
||||
#define COMPACT_THRESH_i 8
|
||||
#define INLINE_MAX_i 9
|
||||
#define BLOCK_CYCLES_i 10
|
||||
#define ERASE_VALUE_i 11
|
||||
#define ERASE_CYCLES_i 12
|
||||
#define BADBLOCK_BEHAVIOR_i 13
|
||||
#define POWERLOSS_BEHAVIOR_i 14
|
||||
#define METADATA_MAX_i 9
|
||||
#define INLINE_MAX_i 10
|
||||
#define BLOCK_CYCLES_i 11
|
||||
#define ERASE_VALUE_i 12
|
||||
#define ERASE_CYCLES_i 13
|
||||
#define BADBLOCK_BEHAVIOR_i 14
|
||||
#define POWERLOSS_BEHAVIOR_i 15
|
||||
|
||||
#define READ_SIZE bench_define(READ_SIZE_i)
|
||||
#define PROG_SIZE bench_define(PROG_SIZE_i)
|
||||
@@ -112,6 +113,7 @@ intmax_t bench_define(size_t define);
|
||||
#define CACHE_SIZE bench_define(CACHE_SIZE_i)
|
||||
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
|
||||
#define COMPACT_THRESH bench_define(COMPACT_THRESH_i)
|
||||
#define METADATA_MAX bench_define(METADATA_MAX_i)
|
||||
#define INLINE_MAX bench_define(INLINE_MAX_i)
|
||||
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
|
||||
#define ERASE_VALUE bench_define(ERASE_VALUE_i)
|
||||
@@ -129,6 +131,7 @@ intmax_t bench_define(size_t define);
|
||||
BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
|
||||
BENCH_DEF(LOOKAHEAD_SIZE, 16) \
|
||||
BENCH_DEF(COMPACT_THRESH, 0) \
|
||||
BENCH_DEF(METADATA_MAX, 0) \
|
||||
BENCH_DEF(INLINE_MAX, 0) \
|
||||
BENCH_DEF(BLOCK_CYCLES, -1) \
|
||||
BENCH_DEF(ERASE_VALUE, 0xff) \
|
||||
@@ -137,7 +140,7 @@ intmax_t bench_define(size_t define);
|
||||
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
|
||||
|
||||
#define BENCH_GEOMETRY_DEFINE_COUNT 4
|
||||
#define BENCH_IMPLICIT_DEFINE_COUNT 15
|
||||
#define BENCH_IMPLICIT_DEFINE_COUNT 16
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1347,6 +1347,7 @@ static void run_powerloss_none(
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
.compact_thresh = COMPACT_THRESH,
|
||||
.metadata_max = METADATA_MAX,
|
||||
.inline_max = INLINE_MAX,
|
||||
#ifdef LFS_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
@@ -1425,6 +1426,7 @@ static void run_powerloss_linear(
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
.compact_thresh = COMPACT_THRESH,
|
||||
.metadata_max = METADATA_MAX,
|
||||
.inline_max = INLINE_MAX,
|
||||
#ifdef LFS_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
@@ -1520,6 +1522,7 @@ static void run_powerloss_log(
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
.compact_thresh = COMPACT_THRESH,
|
||||
.metadata_max = METADATA_MAX,
|
||||
.inline_max = INLINE_MAX,
|
||||
#ifdef LFS_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
@@ -1613,6 +1616,7 @@ static void run_powerloss_cycles(
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
.compact_thresh = COMPACT_THRESH,
|
||||
.metadata_max = METADATA_MAX,
|
||||
.inline_max = INLINE_MAX,
|
||||
#ifdef LFS_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
@@ -1804,6 +1808,7 @@ static void run_powerloss_exhaustive(
|
||||
.cache_size = CACHE_SIZE,
|
||||
.lookahead_size = LOOKAHEAD_SIZE,
|
||||
.compact_thresh = COMPACT_THRESH,
|
||||
.metadata_max = METADATA_MAX,
|
||||
.inline_max = INLINE_MAX,
|
||||
#ifdef LFS_MULTIVERSION
|
||||
.disk_version = DISK_VERSION,
|
||||
|
||||
@@ -89,13 +89,14 @@ intmax_t test_define(size_t define);
|
||||
#define CACHE_SIZE_i 6
|
||||
#define LOOKAHEAD_SIZE_i 7
|
||||
#define COMPACT_THRESH_i 8
|
||||
#define INLINE_MAX_i 9
|
||||
#define BLOCK_CYCLES_i 10
|
||||
#define ERASE_VALUE_i 11
|
||||
#define ERASE_CYCLES_i 12
|
||||
#define BADBLOCK_BEHAVIOR_i 13
|
||||
#define POWERLOSS_BEHAVIOR_i 14
|
||||
#define DISK_VERSION_i 15
|
||||
#define METADATA_MAX_i 9
|
||||
#define INLINE_MAX_i 10
|
||||
#define BLOCK_CYCLES_i 11
|
||||
#define ERASE_VALUE_i 12
|
||||
#define ERASE_CYCLES_i 13
|
||||
#define BADBLOCK_BEHAVIOR_i 14
|
||||
#define POWERLOSS_BEHAVIOR_i 15
|
||||
#define DISK_VERSION_i 16
|
||||
|
||||
#define READ_SIZE TEST_DEFINE(READ_SIZE_i)
|
||||
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i)
|
||||
@@ -106,6 +107,7 @@ intmax_t test_define(size_t define);
|
||||
#define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i)
|
||||
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
|
||||
#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i)
|
||||
#define METADATA_MAX TEST_DEFINE(METADATA_MAX_i)
|
||||
#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i)
|
||||
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
|
||||
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i)
|
||||
@@ -124,6 +126,7 @@ intmax_t test_define(size_t define);
|
||||
TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
|
||||
TEST_DEF(LOOKAHEAD_SIZE, 16) \
|
||||
TEST_DEF(COMPACT_THRESH, 0) \
|
||||
TEST_DEF(METADATA_MAX, 0) \
|
||||
TEST_DEF(INLINE_MAX, 0) \
|
||||
TEST_DEF(BLOCK_CYCLES, -1) \
|
||||
TEST_DEF(ERASE_VALUE, 0xff) \
|
||||
@@ -133,7 +136,7 @@ intmax_t test_define(size_t define);
|
||||
TEST_DEF(DISK_VERSION, 0)
|
||||
|
||||
#define TEST_GEOMETRY_DEFINE_COUNT 4
|
||||
#define TEST_IMPLICIT_DEFINE_COUNT 16
|
||||
#define TEST_IMPLICIT_DEFINE_COUNT 17
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,17 +8,22 @@ defines.FILES = 3
|
||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||
defines.GC = [false, true]
|
||||
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||
lfs_file_t files[FILES];
|
||||
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_mkdir(&lfs, "breakfast") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
@@ -39,7 +44,7 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
@@ -62,17 +67,22 @@ defines.FILES = 3
|
||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||
defines.GC = [false, true]
|
||||
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_mkdir(&lfs, "breakfast") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
lfs_file_t file;
|
||||
@@ -91,7 +101,7 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
@@ -113,19 +123,24 @@ code = '''
|
||||
defines.FILES = 3
|
||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||
defines.CYCLES = [1, 10]
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||
lfs_file_t files[FILES];
|
||||
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
|
||||
for (int c = 0; c < CYCLES; c++) {
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_mkdir(&lfs, "breakfast") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
@@ -143,7 +158,7 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
@@ -159,7 +174,7 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
@@ -175,19 +190,24 @@ code = '''
|
||||
defines.FILES = 3
|
||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||
defines.CYCLES = [1, 10]
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
|
||||
for (int c = 0; c < CYCLES; c++) {
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_mkdir(&lfs, "breakfast") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
for (int n = 0; n < FILES; n++) {
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
char path[1024];
|
||||
sprintf(path, "breakfast/%s", names[n]);
|
||||
lfs_file_t file;
|
||||
@@ -232,10 +252,15 @@ code = '''
|
||||
|
||||
# exhaustion test
|
||||
[cases.test_alloc_exhaustion]
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_file_t file;
|
||||
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
||||
size_t size = strlen("exhaustion");
|
||||
@@ -263,7 +288,7 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
||||
size = strlen("exhaustion");
|
||||
lfs_file_size(&lfs, &file) => size;
|
||||
@@ -276,10 +301,15 @@ code = '''
|
||||
# exhaustion wraparound test
|
||||
[cases.test_alloc_exhaustion_wraparound]
|
||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
|
||||
lfs_file_t file;
|
||||
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
|
||||
@@ -317,7 +347,7 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
||||
size = strlen("exhaustion");
|
||||
lfs_file_size(&lfs, &file) => size;
|
||||
@@ -330,10 +360,15 @@ code = '''
|
||||
|
||||
# dir exhaustion test
|
||||
[cases.test_alloc_dir_exhaustion]
|
||||
defines.INFER_BC = [false, true]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
struct lfs_config cfg_ = *cfg;
|
||||
if (INFER_BC) {
|
||||
cfg_.block_count = 0;
|
||||
}
|
||||
lfs_mount(&lfs, &cfg_) => 0;
|
||||
|
||||
// find out max file size
|
||||
lfs_mkdir(&lfs, "exhaustiondir") => 0;
|
||||
|
||||
@@ -181,6 +181,10 @@ code = '''
|
||||
defines.N = [5, 11]
|
||||
if = 'BLOCK_COUNT >= 4*N'
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
@@ -439,6 +443,10 @@ code = '''
|
||||
defines.N = [5, 25]
|
||||
if = 'N < BLOCK_COUNT/2'
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
@@ -747,6 +755,11 @@ code = '''
|
||||
lfs_file_open(&lfs, &file, "potato",
|
||||
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR;
|
||||
|
||||
lfs_file_open(&lfs, &file, "tacoto", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_rename(&lfs, "tacoto", "potato") => LFS_ERR_ISDIR;
|
||||
lfs_rename(&lfs, "potato", "tacoto") => LFS_ERR_NOTDIR;
|
||||
|
||||
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
|
||||
lfs_file_open(&lfs, &file, "/",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
|
||||
@@ -770,6 +783,10 @@ code = '''
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(strcmp(info.name, "potato") == 0);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(strcmp(info.name, "tacoto") == 0);
|
||||
assert(info.size == 0);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
@@ -790,6 +807,10 @@ code = '''
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(strcmp(info.name, "potato") == 0);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(strcmp(info.name, "tacoto") == 0);
|
||||
assert(info.size == 0);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
@@ -310,6 +310,10 @@ defines.SIZE = [32, 0, 7, 2049]
|
||||
defines.CHUNKSIZE = [31, 16, 65]
|
||||
defines.INLINE_MAX = [0, -1, 8]
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
@@ -500,6 +504,10 @@ code = '''
|
||||
[cases.test_files_many_power_loss]
|
||||
defines.N = 300
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
|
||||
@@ -195,6 +195,10 @@ code = '''
|
||||
defines.SIZE = [10, 100]
|
||||
defines.FILES = [4, 10, 26]
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_file_t files[FILES];
|
||||
|
||||
@@ -357,6 +357,10 @@ code = '''
|
||||
|
||||
[cases.test_move_reentrant_file]
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
@@ -839,6 +843,10 @@ code = '''
|
||||
|
||||
[cases.test_reentrant_dir]
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
|
||||
@@ -329,6 +329,10 @@ code = '''
|
||||
# must be power-of-2 for quadratic probing to be exhaustive
|
||||
defines.COUNT = [4, 64, 128]
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
|
||||
@@ -14,6 +14,24 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# make sure the magic string "littlefs" is always at offset=8
|
||||
[cases.test_superblocks_magic]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
|
||||
// check our magic string
|
||||
//
|
||||
// note if we lose power we may not have the magic string in both blocks!
|
||||
// but we don't lose power in this test so we can assert the magic string
|
||||
// is present in both
|
||||
uint8_t magic[lfs_max(16, READ_SIZE)];
|
||||
cfg->read(cfg, 0, 0, magic, lfs_max(16, READ_SIZE)) => 0;
|
||||
assert(memcmp(&magic[8], "littlefs", 8) == 0);
|
||||
cfg->read(cfg, 1, 0, magic, lfs_max(16, READ_SIZE)) => 0;
|
||||
assert(memcmp(&magic[8], "littlefs", 8) == 0);
|
||||
'''
|
||||
|
||||
# mount/unmount from interpretting a previous superblock block_count
|
||||
[cases.test_superblocks_mount_unknown_block_count]
|
||||
code = '''
|
||||
@@ -28,10 +46,13 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
|
||||
# reentrant format
|
||||
[cases.test_superblocks_reentrant_format]
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
@@ -131,6 +152,39 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# make sure the magic string "littlefs" is always at offset=8
|
||||
[cases.test_superblocks_magic_expand]
|
||||
defines.BLOCK_CYCLES = [32, 33, 1]
|
||||
defines.N = [10, 100, 1000]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
lfs_file_t file;
|
||||
lfs_file_open(&lfs, &file, "dummy",
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
struct lfs_info info;
|
||||
lfs_stat(&lfs, "dummy", &info) => 0;
|
||||
assert(strcmp(info.name, "dummy") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
lfs_remove(&lfs, "dummy") => 0;
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// check our magic string
|
||||
//
|
||||
// note if we lose power we may not have the magic string in both blocks!
|
||||
// but we don't lose power in this test so we can assert the magic string
|
||||
// is present in both
|
||||
uint8_t magic[lfs_max(16, READ_SIZE)];
|
||||
cfg->read(cfg, 0, 0, magic, lfs_max(16, READ_SIZE)) => 0;
|
||||
assert(memcmp(&magic[8], "littlefs", 8) == 0);
|
||||
cfg->read(cfg, 1, 0, magic, lfs_max(16, READ_SIZE)) => 0;
|
||||
assert(memcmp(&magic[8], "littlefs", 8) == 0);
|
||||
'''
|
||||
|
||||
# expanding superblock with power cycle
|
||||
[cases.test_superblocks_expand_power_cycle]
|
||||
defines.BLOCK_CYCLES = [32, 33, 1]
|
||||
@@ -174,6 +228,10 @@ code = '''
|
||||
defines.BLOCK_CYCLES = [2, 1]
|
||||
defines.N = 24
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
@@ -213,6 +271,7 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
|
||||
# mount with unknown block_count
|
||||
[cases.test_superblocks_unknown_blocks]
|
||||
code = '''
|
||||
@@ -464,3 +523,30 @@ code = '''
|
||||
assert(memcmp(buffer, "hello!", 6) == 0);
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that metadata_max does not cause problems for superblock compaction
|
||||
[cases.test_superblocks_metadata_max]
|
||||
defines.METADATA_MAX = [
|
||||
'lfs_max(512, PROG_SIZE)',
|
||||
'lfs_max(BLOCK_SIZE/2, PROG_SIZE)',
|
||||
'BLOCK_SIZE'
|
||||
]
|
||||
defines.N = [10, 100, 1000]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
lfs_file_t file;
|
||||
char name[256];
|
||||
sprintf(name, "hello%03x", i);
|
||||
lfs_file_open(&lfs, &file, name,
|
||||
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
struct lfs_info info;
|
||||
lfs_stat(&lfs, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
@@ -231,6 +231,10 @@ defines.SMALLSIZE = [4, 512]
|
||||
defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025]
|
||||
defines.LARGESIZE = 2048
|
||||
reentrant = true
|
||||
defines.POWERLOSS_BEHAVIOR = [
|
||||
'LFS_EMUBD_POWERLOSS_NOOP',
|
||||
'LFS_EMUBD_POWERLOSS_OOO',
|
||||
]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
int err = lfs_mount(&lfs, cfg);
|
||||
|
||||
Reference in New Issue
Block a user