forked from Imagelibrary/littlefs
Compare commits
32 Commits
fix-sync-o
...
fix-traili
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
999ef6656f | ||
|
|
b735c8fd7f | ||
|
|
30947054d4 | ||
|
|
80ca1ea300 | ||
|
|
815f0d85a5 | ||
|
|
dc92dec6d3 | ||
|
|
a6035071be | ||
|
|
232e736aae | ||
|
|
0de0389c6f | ||
|
|
b78afe2518 | ||
|
|
798073c2a7 | ||
|
|
7db9e1663a | ||
|
|
2c4b262c35 | ||
|
|
72a4b57f4e | ||
|
|
6e7269890a | ||
|
|
d01280e649 | ||
|
|
6e52140d51 | ||
|
|
0bbb8bc88b | ||
|
|
78082336e7 | ||
|
|
8336ecd203 | ||
|
|
68d28b5114 | ||
|
|
1bc14933b7 | ||
|
|
01b6a47ea8 | ||
|
|
749a45650f | ||
|
|
11b036cc6c | ||
|
|
25ee90fdf1 | ||
|
|
a60a986c9c | ||
|
|
4dd30c1b8f | ||
|
|
5c0d332ecd | ||
|
|
cf68333a55 | ||
|
|
2752d8c486 | ||
|
|
ddbfcaa722 |
29
.github/workflows/release.yml
vendored
29
.github/workflows/release.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
github.event.workflow_run.head_sha == github.sha}}
|
github.event.workflow_run.head_sha == github.sha}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{github.event.workflow_run.head_sha}}
|
ref: ${{github.event.workflow_run.head_sha}}
|
||||||
# need workflow access since we push branches
|
# need workflow access since we push branches
|
||||||
@@ -30,26 +30,29 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# try to get results from tests
|
# try to get results from tests
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
workflow: ${{github.event.workflow_run.name}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
run_id: ${{github.event.workflow_run.id}}
|
run-id: ${{github.event.workflow_run.id}}
|
||||||
name: sizes
|
pattern: '{sizes,sizes-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: sizes
|
path: sizes
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
workflow: ${{github.event.workflow_run.name}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
run_id: ${{github.event.workflow_run.id}}
|
run-id: ${{github.event.workflow_run.id}}
|
||||||
name: cov
|
pattern: '{cov,cov-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: cov
|
path: cov
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
workflow: ${{github.event.workflow_run.name}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
run_id: ${{github.event.workflow_run.id}}
|
run-id: ${{github.event.workflow_run.id}}
|
||||||
name: bench
|
pattern: '{bench,bench-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: bench
|
path: bench
|
||||||
|
|
||||||
- name: find-version
|
- name: find-version
|
||||||
|
|||||||
18
.github/workflows/status.yml
vendored
18
.github/workflows/status.yml
vendored
@@ -13,12 +13,13 @@ jobs:
|
|||||||
status:
|
status:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
workflow: ${{github.event.workflow_run.name}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
run_id: ${{github.event.workflow_run.id}}
|
run-id: ${{github.event.workflow_run.id}}
|
||||||
name: status
|
pattern: '{status,status-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: status
|
path: status
|
||||||
- name: update-status
|
- name: update-status
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -67,12 +68,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
# generated comment?
|
# generated comment?
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
workflow: ${{github.event.workflow_run.name}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
run_id: ${{github.event.workflow_run.id}}
|
run-id: ${{github.event.workflow_run.id}}
|
||||||
name: comment
|
pattern: '{comment,comment-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: comment
|
path: comment
|
||||||
- name: update-comment
|
- name: update-comment
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|||||||
72
.github/workflows/test.yml
vendored
72
.github/workflows/test.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
arch: [x86_64, thumb, mips, powerpc]
|
arch: [x86_64, thumb, mips, powerpc]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -235,9 +235,9 @@ jobs:
|
|||||||
|
|
||||||
# create size statuses
|
# create size statuses
|
||||||
- name: upload-sizes
|
- name: upload-sizes
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: sizes
|
name: sizes-${{matrix.arch}}
|
||||||
path: sizes
|
path: sizes
|
||||||
- name: status-sizes
|
- name: status-sizes
|
||||||
run: |
|
run: |
|
||||||
@@ -273,16 +273,17 @@ jobs:
|
|||||||
}' | tee status/$(basename $f .csv).json
|
}' | tee status/$(basename $f .csv).json
|
||||||
done
|
done
|
||||||
- name: upload-status-sizes
|
- name: upload-status-sizes
|
||||||
uses: actions/upload-artifact@v2
|
if: ${{matrix.arch == 'x86_64'}}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: status
|
name: status-sizes-${{matrix.arch}}
|
||||||
path: status
|
path: status
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
# create cov statuses
|
# create cov statuses
|
||||||
- name: upload-cov
|
- name: upload-cov
|
||||||
if: ${{matrix.arch == 'x86_64'}}
|
if: ${{matrix.arch == 'x86_64'}}
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: cov
|
name: cov
|
||||||
path: cov
|
path: cov
|
||||||
@@ -317,11 +318,11 @@ jobs:
|
|||||||
target_step: env.STEP,
|
target_step: env.STEP,
|
||||||
}' | tee status/$(basename $f .csv)-$s.json
|
}' | tee status/$(basename $f .csv)-$s.json
|
||||||
done
|
done
|
||||||
- name: upload-status-sizes
|
- name: upload-status-cov
|
||||||
if: ${{matrix.arch == 'x86_64'}}
|
if: ${{matrix.arch == 'x86_64'}}
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: status
|
name: status-cov
|
||||||
path: status
|
path: status
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
@@ -336,7 +337,7 @@ jobs:
|
|||||||
pls: [1, 2]
|
pls: [1, 2]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -361,7 +362,7 @@ jobs:
|
|||||||
test-no-intrinsics:
|
test-no-intrinsics:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -378,7 +379,7 @@ jobs:
|
|||||||
test-multiversion:
|
test-multiversion:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -395,7 +396,7 @@ jobs:
|
|||||||
test-lfs2_0:
|
test-lfs2_0:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -414,7 +415,7 @@ jobs:
|
|||||||
test-valgrind:
|
test-valgrind:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -436,7 +437,7 @@ jobs:
|
|||||||
test-clang:
|
test-clang:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -459,7 +460,7 @@ jobs:
|
|||||||
bench:
|
bench:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -491,7 +492,7 @@ jobs:
|
|||||||
|
|
||||||
# create bench statuses
|
# create bench statuses
|
||||||
- name: upload-bench
|
- name: upload-bench
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: bench
|
name: bench
|
||||||
path: bench
|
path: bench
|
||||||
@@ -525,9 +526,9 @@ jobs:
|
|||||||
}' | tee status/$(basename $f .csv)-$s.json
|
}' | tee status/$(basename $f .csv)-$s.json
|
||||||
done
|
done
|
||||||
- name: upload-status-bench
|
- name: upload-status-bench
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: status
|
name: status-bench
|
||||||
path: status
|
path: status
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
@@ -535,10 +536,10 @@ jobs:
|
|||||||
test-compat:
|
test-compat:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
# checkout the current pr target into lfsp
|
# checkout the current pr target into lfsp
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
with:
|
with:
|
||||||
ref: ${{github.event.pull_request.base.ref}}
|
ref: ${{github.event.pull_request.base.ref}}
|
||||||
@@ -572,7 +573,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{!endsWith(github.ref, '-prefix')}}
|
if: ${{!endsWith(github.ref, '-prefix')}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -582,7 +583,7 @@ jobs:
|
|||||||
gcc --version
|
gcc --version
|
||||||
python3 --version
|
python3 --version
|
||||||
fusermount -V
|
fusermount -V
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: littlefs-project/littlefs-fuse
|
repository: littlefs-project/littlefs-fuse
|
||||||
ref: v2
|
ref: v2
|
||||||
@@ -622,7 +623,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{!endsWith(github.ref, '-prefix')}}
|
if: ${{!endsWith(github.ref, '-prefix')}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: install
|
- name: install
|
||||||
run: |
|
run: |
|
||||||
# need a few things
|
# need a few things
|
||||||
@@ -632,12 +633,12 @@ jobs:
|
|||||||
gcc --version
|
gcc --version
|
||||||
python3 --version
|
python3 --version
|
||||||
fusermount -V
|
fusermount -V
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: littlefs-project/littlefs-fuse
|
repository: littlefs-project/littlefs-fuse
|
||||||
ref: v2
|
ref: v2
|
||||||
path: v2
|
path: v2
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: littlefs-project/littlefs-fuse
|
repository: littlefs-project/littlefs-fuse
|
||||||
ref: v1
|
ref: v1
|
||||||
@@ -694,7 +695,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [test, bench]
|
needs: [test, bench]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
- name: install
|
- name: install
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
@@ -704,23 +705,26 @@ jobs:
|
|||||||
pip3 install toml
|
pip3 install toml
|
||||||
gcc --version
|
gcc --version
|
||||||
python3 --version
|
python3 --version
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: sizes
|
pattern: '{sizes,sizes-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: sizes
|
path: sizes
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: cov
|
pattern: '{cov,cov-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: cov
|
path: cov
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v4
|
||||||
if: ${{github.event_name == 'pull_request'}}
|
if: ${{github.event_name == 'pull_request'}}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: bench
|
pattern: '{bench,bench-*}'
|
||||||
|
merge-multiple: true
|
||||||
path: bench
|
path: bench
|
||||||
|
|
||||||
# try to find results from tests
|
# try to find results from tests
|
||||||
@@ -862,7 +866,7 @@ jobs:
|
|||||||
body: $comment,
|
body: $comment,
|
||||||
}' | tee comment/comment.json
|
}' | tee comment/comment.json
|
||||||
- name: upload-comment
|
- name: upload-comment
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: comment
|
name: comment
|
||||||
path: 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
|
to use littlefs in a Rust-friendly API, reaping the benefits of Rust's memory
|
||||||
safety and other guarantees.
|
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-img-viewer] - A memory-efficient web application for viewing
|
||||||
littlefs disk images in your web browser.
|
littlefs disk images in your web browser.
|
||||||
|
|
||||||
- [mklfs] - A command line tool built by the [Lua RTOS] guys for making
|
- [mklfs] - A command line tool for creating littlefs images. Used in the Lua
|
||||||
littlefs images from a host PC. Supports Windows, Mac OS, and Linux.
|
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
|
- [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.
|
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
|
for microcontroller-scale devices. Due to limitations of FAT it can't provide
|
||||||
power-loss resilience, but it does allow easy interop with PCs.
|
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
|
[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
|
[littlefs-fuse]: https://github.com/geky/littlefs-fuse
|
||||||
[FUSE]: https://github.com/libfuse/libfuse
|
[FUSE]: https://github.com/libfuse/libfuse
|
||||||
[littlefs-js]: https://github.com/geky/littlefs-js
|
[littlefs-js]: https://github.com/geky/littlefs-js
|
||||||
[littlefs-js-demo]:http://littlefs.geky.net/demo.html
|
[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
|
[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
|
[Mbed OS]: https://github.com/armmbed/mbed-os
|
||||||
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html
|
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html
|
||||||
[SPIFFS]: https://github.com/pellepl/spiffs
|
[SPIFFS]: https://github.com/pellepl/spiffs
|
||||||
[Dhara]: https://github.com/dlbeer/dhara
|
[Dhara]: https://github.com/dlbeer/dhara
|
||||||
[ChaN's FatFs]: http://elm-chan.org/fsw/ff/00index_e.html
|
[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.
|
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
|
The superblock must always be the first entry (id 0) in the metadata pair, and
|
||||||
as be the first entry written to the block. This means that the superblock
|
the name tag must always be the first tag in the metadata pair. This makes it
|
||||||
entry can be read from a device using offsets alone.
|
so that the magic string "littlefs" will always reside at offset=8 in a valid
|
||||||
|
littlefs superblock.
|
||||||
|
|
||||||
---
|
---
|
||||||
#### `0x2xx` LFS_TYPE_STRUCT
|
#### `0x2xx` LFS_TYPE_STRUCT
|
||||||
|
|||||||
117
lfs.c
117
lfs.c
@@ -282,6 +282,21 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
|
|||||||
|
|
||||||
|
|
||||||
/// Small type-level utilities ///
|
/// Small type-level utilities ///
|
||||||
|
|
||||||
|
// some operations on paths
|
||||||
|
static inline lfs_size_t lfs_path_namelen(const char *path) {
|
||||||
|
return strcspn(path, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool lfs_path_islast(const char *path) {
|
||||||
|
lfs_size_t namelen = lfs_path_namelen(path);
|
||||||
|
return path[namelen + strspn(path + namelen, "/")] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool lfs_path_isdir(const char *path) {
|
||||||
|
return path[lfs_path_namelen(path)] != '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// operations on block pairs
|
// operations on block pairs
|
||||||
static inline void lfs_pair_swap(lfs_block_t pair[2]) {
|
static inline void lfs_pair_swap(lfs_block_t pair[2]) {
|
||||||
lfs_block_t t = pair[0];
|
lfs_block_t t = pair[0];
|
||||||
@@ -688,7 +703,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
|
|||||||
if (lfs->lookahead.ckpoint <= 0) {
|
if (lfs->lookahead.ckpoint <= 0) {
|
||||||
LFS_ERROR("No more free space 0x%"PRIx32,
|
LFS_ERROR("No more free space 0x%"PRIx32,
|
||||||
(lfs->lookahead.start + lfs->lookahead.next)
|
(lfs->lookahead.start + lfs->lookahead.next)
|
||||||
% lfs->cfg->block_count);
|
% lfs->block_count);
|
||||||
return LFS_ERR_NOSPC;
|
return LFS_ERR_NOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,11 +725,14 @@ static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir,
|
|||||||
lfs_tag_t ntag = dir->etag;
|
lfs_tag_t ntag = dir->etag;
|
||||||
lfs_stag_t gdiff = 0;
|
lfs_stag_t gdiff = 0;
|
||||||
|
|
||||||
|
// synthetic moves
|
||||||
if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) &&
|
if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) &&
|
||||||
lfs_tag_id(gmask) != 0 &&
|
lfs_tag_id(gmask) != 0) {
|
||||||
lfs_tag_id(lfs->gdisk.tag) <= lfs_tag_id(gtag)) {
|
if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(gtag)) {
|
||||||
// synthetic moves
|
return LFS_ERR_NOENT;
|
||||||
gdiff -= LFS_MKTAG(0, 1, 0);
|
} 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)
|
// iterate over dir block backwards (for faster lookups)
|
||||||
@@ -1458,32 +1476,46 @@ static int lfs_dir_find_match(void *data,
|
|||||||
return LFS_CMP_EQ;
|
return LFS_CMP_EQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lfs_dir_find tries to set path and id even if file is not found
|
||||||
|
//
|
||||||
|
// returns:
|
||||||
|
// - 0 if file is found
|
||||||
|
// - LFS_ERR_NOENT if file or parent is not found
|
||||||
|
// - LFS_ERR_NOTDIR if parent is not a dir
|
||||||
static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
|
static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
|
||||||
const char **path, uint16_t *id) {
|
const char **path, uint16_t *id) {
|
||||||
// we reduce path to a single name if we can find it
|
// we reduce path to a single name if we can find it
|
||||||
const char *name = *path;
|
const char *name = *path;
|
||||||
if (id) {
|
|
||||||
*id = 0x3ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
// default to root dir
|
// default to root dir
|
||||||
lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0);
|
lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0);
|
||||||
dir->tail[0] = lfs->root[0];
|
dir->tail[0] = lfs->root[0];
|
||||||
dir->tail[1] = lfs->root[1];
|
dir->tail[1] = lfs->root[1];
|
||||||
|
|
||||||
|
// empty paths are not allowed
|
||||||
|
if (*name == '\0') {
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
nextname:
|
nextname:
|
||||||
// skip slashes
|
// skip slashes if we're a directory
|
||||||
name += strspn(name, "/");
|
if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
|
||||||
|
name += strspn(name, "/");
|
||||||
|
}
|
||||||
lfs_size_t namelen = strcspn(name, "/");
|
lfs_size_t namelen = strcspn(name, "/");
|
||||||
|
|
||||||
// skip '.' and root '..'
|
// skip '.'
|
||||||
if ((namelen == 1 && memcmp(name, ".", 1) == 0) ||
|
if (namelen == 1 && memcmp(name, ".", 1) == 0) {
|
||||||
(namelen == 2 && memcmp(name, "..", 2) == 0)) {
|
|
||||||
name += namelen;
|
name += namelen;
|
||||||
goto nextname;
|
goto nextname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// error on unmatched '..', trying to go above root?
|
||||||
|
if (namelen == 2 && memcmp(name, "..", 2) == 0) {
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
// skip if matched by '..' in name
|
// skip if matched by '..' in name
|
||||||
const char *suffix = name + namelen;
|
const char *suffix = name + namelen;
|
||||||
lfs_size_t sufflen;
|
lfs_size_t sufflen;
|
||||||
@@ -1495,7 +1527,9 @@ nextname:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
|
if (sufflen == 1 && memcmp(suffix, ".", 1) == 0) {
|
||||||
|
// noop
|
||||||
|
} else if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
|
||||||
depth -= 1;
|
depth -= 1;
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
name = suffix + sufflen;
|
name = suffix + sufflen;
|
||||||
@@ -1509,14 +1543,14 @@ nextname:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// found path
|
// found path
|
||||||
if (name[0] == '\0') {
|
if (*name == '\0') {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update what we've found so far
|
// update what we've found so far
|
||||||
*path = name;
|
*path = name;
|
||||||
|
|
||||||
// only continue if we hit a directory
|
// only continue if we're a directory
|
||||||
if (lfs_tag_type3(tag) != LFS_TYPE_DIR) {
|
if (lfs_tag_type3(tag) != LFS_TYPE_DIR) {
|
||||||
return LFS_ERR_NOTDIR;
|
return LFS_ERR_NOTDIR;
|
||||||
}
|
}
|
||||||
@@ -1536,8 +1570,7 @@ nextname:
|
|||||||
tag = lfs_dir_fetchmatch(lfs, dir, dir->tail,
|
tag = lfs_dir_fetchmatch(lfs, dir, dir->tail,
|
||||||
LFS_MKTAG(0x780, 0, 0),
|
LFS_MKTAG(0x780, 0, 0),
|
||||||
LFS_MKTAG(LFS_TYPE_NAME, 0, namelen),
|
LFS_MKTAG(LFS_TYPE_NAME, 0, namelen),
|
||||||
// are we last name?
|
id,
|
||||||
(strchr(name, '/') == NULL) ? id : NULL,
|
|
||||||
lfs_dir_find_match, &(struct lfs_dir_find_match){
|
lfs_dir_find_match, &(struct lfs_dir_find_match){
|
||||||
lfs, name, namelen});
|
lfs, name, namelen});
|
||||||
if (tag < 0) {
|
if (tag < 0) {
|
||||||
@@ -2188,7 +2221,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
|
// we can do, we'll error later if we've become frozen
|
||||||
LFS_WARN("Unable to expand superblock");
|
LFS_WARN("Unable to expand superblock");
|
||||||
} else {
|
} else {
|
||||||
end = begin;
|
// duplicate the superblock entry into the new superblock
|
||||||
|
end = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2355,7 +2389,9 @@ fixmlist:;
|
|||||||
|
|
||||||
while (d->id >= d->m.count && d->m.split) {
|
while (d->id >= d->m.count && d->m.split) {
|
||||||
// we split and id is on tail now
|
// 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);
|
int err = lfs_dir_fetch(lfs, &d->m, d->m.tail);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -2597,12 +2633,12 @@ static int lfs_mkdir_(lfs_t *lfs, const char *path) {
|
|||||||
cwd.next = lfs->mlist;
|
cwd.next = lfs->mlist;
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
err = lfs_dir_find(lfs, &cwd.m, &path, &id);
|
err = lfs_dir_find(lfs, &cwd.m, &path, &id);
|
||||||
if (!(err == LFS_ERR_NOENT && id != 0x3ff)) {
|
if (!(err == LFS_ERR_NOENT && lfs_path_islast(path))) {
|
||||||
return (err < 0) ? err : LFS_ERR_EXIST;
|
return (err < 0) ? err : LFS_ERR_EXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that name fits
|
// check that name fits
|
||||||
lfs_size_t nlen = strlen(path);
|
lfs_size_t nlen = lfs_path_namelen(path);
|
||||||
if (nlen > lfs->name_max) {
|
if (nlen > lfs->name_max) {
|
||||||
return LFS_ERR_NAMETOOLONG;
|
return LFS_ERR_NAMETOOLONG;
|
||||||
}
|
}
|
||||||
@@ -3051,7 +3087,7 @@ static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file,
|
|||||||
|
|
||||||
// allocate entry for file if it doesn't exist
|
// allocate entry for file if it doesn't exist
|
||||||
lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
|
lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
|
||||||
if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) {
|
if (tag < 0 && !(tag == LFS_ERR_NOENT && lfs_path_islast(path))) {
|
||||||
err = tag;
|
err = tag;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@@ -3071,8 +3107,14 @@ static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't allow trailing slashes
|
||||||
|
if (lfs_path_isdir(path)) {
|
||||||
|
err = LFS_ERR_NOTDIR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
// check that name fits
|
// check that name fits
|
||||||
lfs_size_t nlen = strlen(path);
|
lfs_size_t nlen = lfs_path_namelen(path);
|
||||||
if (nlen > lfs->name_max) {
|
if (nlen > lfs->name_max) {
|
||||||
err = LFS_ERR_NAMETOOLONG;
|
err = LFS_ERR_NAMETOOLONG;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -3836,6 +3878,12 @@ static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) {
|
|||||||
return (int)tag;
|
return (int)tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only allow trailing slashes on dirs
|
||||||
|
if (strchr(path, '/') != NULL
|
||||||
|
&& lfs_tag_type3(tag) != LFS_TYPE_DIR) {
|
||||||
|
return LFS_ERR_NOTDIR;
|
||||||
|
}
|
||||||
|
|
||||||
return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info);
|
return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3938,7 +3986,7 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
uint16_t newid;
|
uint16_t newid;
|
||||||
lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid);
|
lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid);
|
||||||
if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) &&
|
if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) &&
|
||||||
!(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) {
|
!(prevtag == LFS_ERR_NOENT && lfs_path_islast(newpath))) {
|
||||||
return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL;
|
return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3949,8 +3997,14 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
struct lfs_mlist prevdir;
|
struct lfs_mlist prevdir;
|
||||||
prevdir.next = lfs->mlist;
|
prevdir.next = lfs->mlist;
|
||||||
if (prevtag == LFS_ERR_NOENT) {
|
if (prevtag == LFS_ERR_NOENT) {
|
||||||
|
// if we're a file, don't allow trailing slashes
|
||||||
|
if (lfs_path_isdir(newpath)
|
||||||
|
&& lfs_tag_type3(oldtag) != LFS_TYPE_DIR) {
|
||||||
|
return LFS_ERR_NOTDIR;
|
||||||
|
}
|
||||||
|
|
||||||
// check that name fits
|
// check that name fits
|
||||||
lfs_size_t nlen = strlen(newpath);
|
lfs_size_t nlen = lfs_path_namelen(newpath);
|
||||||
if (nlen > lfs->name_max) {
|
if (nlen > lfs->name_max) {
|
||||||
return LFS_ERR_NAMETOOLONG;
|
return LFS_ERR_NAMETOOLONG;
|
||||||
}
|
}
|
||||||
@@ -4010,7 +4064,8 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
{LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT,
|
{LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT,
|
||||||
LFS_TYPE_DELETE, newid, 0), NULL},
|
LFS_TYPE_DELETE, newid, 0), NULL},
|
||||||
{LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL},
|
{LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL},
|
||||||
{LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)), newpath},
|
{LFS_MKTAG(lfs_tag_type3(oldtag),
|
||||||
|
newid, lfs_path_namelen(newpath)), newpath},
|
||||||
{LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd},
|
{LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd},
|
||||||
{LFS_MKTAG_IF(samepair,
|
{LFS_MKTAG_IF(samepair,
|
||||||
LFS_TYPE_DELETE, newoldid, 0), NULL}));
|
LFS_TYPE_DELETE, newoldid, 0), NULL}));
|
||||||
@@ -4463,6 +4518,7 @@ static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
// found older minor version? set an in-device only bit in the
|
// found older minor version? set an in-device only bit in the
|
||||||
// gstate so we know we need to rewrite the superblock before
|
// gstate so we know we need to rewrite the superblock before
|
||||||
// the first write
|
// the first write
|
||||||
|
bool needssuperblock = false;
|
||||||
if (minor_version < lfs_fs_disk_version_minor(lfs)) {
|
if (minor_version < lfs_fs_disk_version_minor(lfs)) {
|
||||||
LFS_DEBUG("Found older minor version "
|
LFS_DEBUG("Found older minor version "
|
||||||
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
|
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
|
||||||
@@ -4470,10 +4526,11 @@ static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
minor_version,
|
minor_version,
|
||||||
lfs_fs_disk_version_major(lfs),
|
lfs_fs_disk_version_major(lfs),
|
||||||
lfs_fs_disk_version_minor(lfs));
|
lfs_fs_disk_version_minor(lfs));
|
||||||
// note this bit is reserved on disk, so fetching more gstate
|
needssuperblock = true;
|
||||||
// will not interfere here
|
|
||||||
lfs_fs_prepsuperblock(lfs, true);
|
|
||||||
}
|
}
|
||||||
|
// note this bit is reserved on disk, so fetching more gstate
|
||||||
|
// will not interfere here
|
||||||
|
lfs_fs_prepsuperblock(lfs, needssuperblock);
|
||||||
|
|
||||||
// check superblock configuration
|
// check superblock configuration
|
||||||
if (superblock.name_max) {
|
if (superblock.name_max) {
|
||||||
|
|||||||
16
lfs.h
16
lfs.h
@@ -59,7 +59,8 @@ typedef uint32_t lfs_block_t;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Maximum size of custom attributes in bytes, may be redefined, but there is
|
// 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
|
#ifndef LFS_ATTR_MAX
|
||||||
#define LFS_ATTR_MAX 1022
|
#define LFS_ATTR_MAX 1022
|
||||||
#endif
|
#endif
|
||||||
@@ -203,7 +204,8 @@ struct lfs_config {
|
|||||||
// program sizes.
|
// program sizes.
|
||||||
lfs_size_t block_size;
|
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;
|
lfs_size_t block_count;
|
||||||
|
|
||||||
// Number of erase cycles before littlefs evicts metadata logs and moves
|
// 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
|
// 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
|
// larger names except the size of the info struct which is controlled by
|
||||||
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
|
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on
|
||||||
// superblock and must be respected by other littlefs drivers.
|
// disk when zero.
|
||||||
lfs_size_t name_max;
|
lfs_size_t name_max;
|
||||||
|
|
||||||
// Optional upper limit on files in bytes. No downside for larger files
|
// Optional upper limit on files in bytes. No downside for larger files
|
||||||
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
|
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored
|
||||||
// in superblock and must be respected by other littlefs drivers.
|
// on disk when zero.
|
||||||
lfs_size_t file_max;
|
lfs_size_t file_max;
|
||||||
|
|
||||||
// Optional upper limit on custom attributes in bytes. No downside for
|
// Optional upper limit on custom attributes in bytes. No downside for
|
||||||
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
// 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;
|
lfs_size_t attr_max;
|
||||||
|
|
||||||
// Optional upper limit on total space given to metadata pairs in bytes. On
|
// Optional upper limit on total space given to metadata pairs in bytes. On
|
||||||
|
|||||||
@@ -8,17 +8,22 @@ defines.FILES = 3
|
|||||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||||
defines.GC = [false, true]
|
defines.GC = [false, true]
|
||||||
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
|
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||||
lfs_file_t files[FILES];
|
lfs_file_t files[FILES];
|
||||||
|
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
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_mkdir(&lfs, "breakfast") => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
@@ -39,7 +44,7 @@ code = '''
|
|||||||
}
|
}
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
@@ -62,17 +67,22 @@ defines.FILES = 3
|
|||||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||||
defines.GC = [false, true]
|
defines.GC = [false, true]
|
||||||
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
|
defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||||
|
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
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_mkdir(&lfs, "breakfast") => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
lfs_file_t file;
|
lfs_file_t file;
|
||||||
@@ -91,7 +101,7 @@ code = '''
|
|||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
@@ -113,19 +123,24 @@ code = '''
|
|||||||
defines.FILES = 3
|
defines.FILES = 3
|
||||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||||
defines.CYCLES = [1, 10]
|
defines.CYCLES = [1, 10]
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||||
lfs_file_t files[FILES];
|
lfs_file_t files[FILES];
|
||||||
|
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
lfs_format(&lfs, cfg) => 0;
|
||||||
|
struct lfs_config cfg_ = *cfg;
|
||||||
|
if (INFER_BC) {
|
||||||
|
cfg_.block_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int c = 0; c < CYCLES; c++) {
|
for (int c = 0; c < CYCLES; c++) {
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
lfs_mkdir(&lfs, "breakfast") => 0;
|
lfs_mkdir(&lfs, "breakfast") => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
@@ -143,7 +158,7 @@ code = '''
|
|||||||
}
|
}
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
@@ -159,7 +174,7 @@ code = '''
|
|||||||
}
|
}
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
@@ -175,19 +190,24 @@ code = '''
|
|||||||
defines.FILES = 3
|
defines.FILES = 3
|
||||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
|
||||||
defines.CYCLES = [1, 10]
|
defines.CYCLES = [1, 10]
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
const char *names[] = {"bacon", "eggs", "pancakes"};
|
const char *names[] = {"bacon", "eggs", "pancakes"};
|
||||||
|
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
lfs_format(&lfs, cfg) => 0;
|
||||||
|
struct lfs_config cfg_ = *cfg;
|
||||||
|
if (INFER_BC) {
|
||||||
|
cfg_.block_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int c = 0; c < CYCLES; c++) {
|
for (int c = 0; c < CYCLES; c++) {
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
lfs_mkdir(&lfs, "breakfast") => 0;
|
lfs_mkdir(&lfs, "breakfast") => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
for (int n = 0; n < FILES; n++) {
|
for (int n = 0; n < FILES; n++) {
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
char path[1024];
|
char path[1024];
|
||||||
sprintf(path, "breakfast/%s", names[n]);
|
sprintf(path, "breakfast/%s", names[n]);
|
||||||
lfs_file_t file;
|
lfs_file_t file;
|
||||||
@@ -232,10 +252,15 @@ code = '''
|
|||||||
|
|
||||||
# exhaustion test
|
# exhaustion test
|
||||||
[cases.test_alloc_exhaustion]
|
[cases.test_alloc_exhaustion]
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
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_t file;
|
||||||
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
|
||||||
size_t size = strlen("exhaustion");
|
size_t size = strlen("exhaustion");
|
||||||
@@ -263,7 +288,7 @@ code = '''
|
|||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
||||||
size = strlen("exhaustion");
|
size = strlen("exhaustion");
|
||||||
lfs_file_size(&lfs, &file) => size;
|
lfs_file_size(&lfs, &file) => size;
|
||||||
@@ -276,10 +301,15 @@ code = '''
|
|||||||
# exhaustion wraparound test
|
# exhaustion wraparound test
|
||||||
[cases.test_alloc_exhaustion_wraparound]
|
[cases.test_alloc_exhaustion_wraparound]
|
||||||
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
|
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
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_t file;
|
||||||
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
|
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
|
||||||
@@ -317,7 +347,7 @@ code = '''
|
|||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
lfs_mount(&lfs, cfg) => 0;
|
lfs_mount(&lfs, &cfg_) => 0;
|
||||||
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
|
||||||
size = strlen("exhaustion");
|
size = strlen("exhaustion");
|
||||||
lfs_file_size(&lfs, &file) => size;
|
lfs_file_size(&lfs, &file) => size;
|
||||||
@@ -330,10 +360,15 @@ code = '''
|
|||||||
|
|
||||||
# dir exhaustion test
|
# dir exhaustion test
|
||||||
[cases.test_alloc_dir_exhaustion]
|
[cases.test_alloc_dir_exhaustion]
|
||||||
|
defines.INFER_BC = [false, true]
|
||||||
code = '''
|
code = '''
|
||||||
lfs_t lfs;
|
lfs_t lfs;
|
||||||
lfs_format(&lfs, cfg) => 0;
|
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
|
// find out max file size
|
||||||
lfs_mkdir(&lfs, "exhaustiondir") => 0;
|
lfs_mkdir(&lfs, "exhaustiondir") => 0;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,24 @@ code = '''
|
|||||||
lfs_unmount(&lfs) => 0;
|
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
|
# mount/unmount from interpretting a previous superblock block_count
|
||||||
[cases.test_superblocks_mount_unknown_block_count]
|
[cases.test_superblocks_mount_unknown_block_count]
|
||||||
code = '''
|
code = '''
|
||||||
@@ -28,7 +46,6 @@ code = '''
|
|||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
# reentrant format
|
# reentrant format
|
||||||
[cases.test_superblocks_reentrant_format]
|
[cases.test_superblocks_reentrant_format]
|
||||||
reentrant = true
|
reentrant = true
|
||||||
@@ -135,6 +152,39 @@ code = '''
|
|||||||
lfs_unmount(&lfs) => 0;
|
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
|
# expanding superblock with power cycle
|
||||||
[cases.test_superblocks_expand_power_cycle]
|
[cases.test_superblocks_expand_power_cycle]
|
||||||
defines.BLOCK_CYCLES = [32, 33, 1]
|
defines.BLOCK_CYCLES = [32, 33, 1]
|
||||||
@@ -221,6 +271,7 @@ code = '''
|
|||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
# mount with unknown block_count
|
# mount with unknown block_count
|
||||||
[cases.test_superblocks_unknown_blocks]
|
[cases.test_superblocks_unknown_blocks]
|
||||||
code = '''
|
code = '''
|
||||||
|
|||||||
Reference in New Issue
Block a user