mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-11-16 12:34:34 +00:00
Merge pull request #1050 from littlefs-project/devel
Minor release: v2.10
This commit is contained in:
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
|
||||||
|
|||||||
71
.github/workflows/test.yml
vendored
71
.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,16 @@ 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
|
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 +317,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 +336,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 +361,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 +378,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 +395,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 +414,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 +436,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 +459,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 +491,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 +525,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 +535,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 +572,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 +582,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 +622,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 +632,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 +694,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 +704,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 +865,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
|
||||||
|
|||||||
@@ -251,6 +251,12 @@ License Identifiers that are here available: http://spdx.org/licenses/
|
|||||||
filesystem over USB. Allows mounting littlefs on a host PC without additional
|
filesystem over USB. Allows mounting littlefs on a host PC without additional
|
||||||
drivers.
|
drivers.
|
||||||
|
|
||||||
|
- [ramcrc32bd] - An example block device using littlefs's 32-bit CRC for
|
||||||
|
error-correction.
|
||||||
|
|
||||||
|
- [ramrsbd] - An example block device using Reed-Solomon codes for
|
||||||
|
error-correction.
|
||||||
|
|
||||||
- [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.
|
||||||
littlefs is available in Mbed OS as the [LittleFileSystem] class.
|
littlefs is available in Mbed OS as the [LittleFileSystem] class.
|
||||||
@@ -281,6 +287,8 @@ License Identifiers that are here available: http://spdx.org/licenses/
|
|||||||
[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
|
||||||
[mklittlefs]: https://github.com/earlephilhower/mklittlefs
|
[mklittlefs]: https://github.com/earlephilhower/mklittlefs
|
||||||
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb
|
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb
|
||||||
|
[ramcrc32bd]: https://github.com/geky/ramcrc32bd
|
||||||
|
[ramrsbd]: https://github.com/geky/ramrsbd
|
||||||
[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
|
||||||
|
|||||||
251
lfs.c
251
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];
|
||||||
@@ -1461,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;
|
||||||
@@ -1498,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;
|
||||||
@@ -1512,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;
|
||||||
}
|
}
|
||||||
@@ -1539,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) {
|
||||||
@@ -2128,13 +2158,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
|
// And we cap at half a block to avoid degenerate cases with
|
||||||
// nearly-full metadata blocks.
|
// 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
|
if (end - split < 0xff
|
||||||
&& size <= lfs_min(
|
&& size <= lfs_min(
|
||||||
lfs->cfg->block_size - 40,
|
metadata_max - 40,
|
||||||
lfs_alignup(
|
lfs_alignup(
|
||||||
(lfs->cfg->metadata_max
|
metadata_max/2,
|
||||||
? lfs->cfg->metadata_max
|
|
||||||
: lfs->cfg->block_size)/2,
|
|
||||||
lfs->cfg->prog_size))) {
|
lfs->cfg->prog_size))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2603,12 +2634,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;
|
||||||
}
|
}
|
||||||
@@ -3057,7 +3088,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;
|
||||||
}
|
}
|
||||||
@@ -3077,8 +3108,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;
|
||||||
@@ -3664,22 +3701,16 @@ static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file,
|
|||||||
static lfs_soff_t lfs_file_seek_(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) {
|
lfs_soff_t off, int whence) {
|
||||||
// find new pos
|
// find new pos
|
||||||
|
//
|
||||||
|
// fortunately for us, littlefs is limited to 31-bit file sizes, so we
|
||||||
|
// don't have to worry too much about integer overflow
|
||||||
lfs_off_t npos = file->pos;
|
lfs_off_t npos = file->pos;
|
||||||
if (whence == LFS_SEEK_SET) {
|
if (whence == LFS_SEEK_SET) {
|
||||||
npos = off;
|
npos = off;
|
||||||
} else if (whence == LFS_SEEK_CUR) {
|
} else if (whence == LFS_SEEK_CUR) {
|
||||||
if ((lfs_soff_t)file->pos + off < 0) {
|
npos = file->pos + (lfs_off_t)off;
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
} else {
|
|
||||||
npos = file->pos + off;
|
|
||||||
}
|
|
||||||
} else if (whence == LFS_SEEK_END) {
|
} else if (whence == LFS_SEEK_END) {
|
||||||
lfs_soff_t res = lfs_file_size_(lfs, file) + off;
|
npos = (lfs_off_t)lfs_file_size_(lfs, file) + (lfs_off_t)off;
|
||||||
if (res < 0) {
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
} else {
|
|
||||||
npos = res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (npos > lfs->file_max) {
|
if (npos > lfs->file_max) {
|
||||||
@@ -3842,6 +3873,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3944,7 +3981,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3955,8 +3992,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;
|
||||||
}
|
}
|
||||||
@@ -4016,7 +4059,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}));
|
||||||
@@ -4173,6 +4217,14 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
// which littlefs currently does not support
|
// which littlefs currently does not support
|
||||||
LFS_ASSERT((bool)0x80000000);
|
LFS_ASSERT((bool)0x80000000);
|
||||||
|
|
||||||
|
// check that the required io functions are provided
|
||||||
|
LFS_ASSERT(lfs->cfg->read != NULL);
|
||||||
|
#ifndef LFS_READONLY
|
||||||
|
LFS_ASSERT(lfs->cfg->prog != NULL);
|
||||||
|
LFS_ASSERT(lfs->cfg->erase != NULL);
|
||||||
|
LFS_ASSERT(lfs->cfg->sync != NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
// validate that the lfs-cfg sizes were initiated properly before
|
// validate that the lfs-cfg sizes were initiated properly before
|
||||||
// performing any arithmetic logics with them
|
// performing any arithmetic logics with them
|
||||||
LFS_ASSERT(lfs->cfg->read_size != 0);
|
LFS_ASSERT(lfs->cfg->read_size != 0);
|
||||||
@@ -4209,6 +4261,15 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1
|
LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1
|
||||||
|| lfs->cfg->compact_thresh <= lfs->cfg->block_size);
|
|| 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
|
// setup read cache
|
||||||
if (lfs->cfg->read_buffer) {
|
if (lfs->cfg->read_buffer) {
|
||||||
lfs->rcache.buffer = lfs->cfg->read_buffer;
|
lfs->rcache.buffer = lfs->cfg->read_buffer;
|
||||||
@@ -4396,6 +4457,30 @@ cleanup:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct lfs_tortoise_t {
|
||||||
|
lfs_block_t pair[2];
|
||||||
|
lfs_size_t i;
|
||||||
|
lfs_size_t period;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int lfs_tortoise_detectcycles(
|
||||||
|
const lfs_mdir_t *dir, struct lfs_tortoise_t *tortoise) {
|
||||||
|
// detect cycles with Brent's algorithm
|
||||||
|
if (lfs_pair_issync(dir->tail, tortoise->pair)) {
|
||||||
|
LFS_WARN("Cycle detected in tail list");
|
||||||
|
return LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
if (tortoise->i == tortoise->period) {
|
||||||
|
tortoise->pair[0] = dir->tail[0];
|
||||||
|
tortoise->pair[1] = dir->tail[1];
|
||||||
|
tortoise->i = 0;
|
||||||
|
tortoise->period *= 2;
|
||||||
|
}
|
||||||
|
tortoise->i += 1;
|
||||||
|
|
||||||
|
return LFS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int lfs_mount_(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);
|
int err = lfs_init(lfs, cfg);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -4404,23 +4489,16 @@ static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
|
|
||||||
// scan directory blocks for superblock and any global updates
|
// scan directory blocks for superblock and any global updates
|
||||||
lfs_mdir_t dir = {.tail = {0, 1}};
|
lfs_mdir_t dir = {.tail = {0, 1}};
|
||||||
lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
|
struct lfs_tortoise_t tortoise = {
|
||||||
lfs_size_t tortoise_i = 1;
|
.pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
|
||||||
lfs_size_t tortoise_period = 1;
|
.i = 1,
|
||||||
|
.period = 1,
|
||||||
|
};
|
||||||
while (!lfs_pair_isnull(dir.tail)) {
|
while (!lfs_pair_isnull(dir.tail)) {
|
||||||
// detect cycles with Brent's algorithm
|
err = lfs_tortoise_detectcycles(&dir, &tortoise);
|
||||||
if (lfs_pair_issync(dir.tail, tortoise)) {
|
if (err < 0) {
|
||||||
LFS_WARN("Cycle detected in tail list");
|
|
||||||
err = LFS_ERR_CORRUPT;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (tortoise_i == tortoise_period) {
|
|
||||||
tortoise[0] = dir.tail[0];
|
|
||||||
tortoise[1] = dir.tail[1];
|
|
||||||
tortoise_i = 0;
|
|
||||||
tortoise_period *= 2;
|
|
||||||
}
|
|
||||||
tortoise_i += 1;
|
|
||||||
|
|
||||||
// fetch next block in tail list
|
// fetch next block in tail list
|
||||||
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
|
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
|
||||||
@@ -4633,22 +4711,17 @@ int lfs_fs_traverse_(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
|
struct lfs_tortoise_t tortoise = {
|
||||||
lfs_size_t tortoise_i = 1;
|
.pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
|
||||||
lfs_size_t tortoise_period = 1;
|
.i = 1,
|
||||||
|
.period = 1,
|
||||||
|
};
|
||||||
|
int err = LFS_ERR_OK;
|
||||||
while (!lfs_pair_isnull(dir.tail)) {
|
while (!lfs_pair_isnull(dir.tail)) {
|
||||||
// detect cycles with Brent's algorithm
|
err = lfs_tortoise_detectcycles(&dir, &tortoise);
|
||||||
if (lfs_pair_issync(dir.tail, tortoise)) {
|
if (err < 0) {
|
||||||
LFS_WARN("Cycle detected in tail list");
|
|
||||||
return LFS_ERR_CORRUPT;
|
return LFS_ERR_CORRUPT;
|
||||||
}
|
}
|
||||||
if (tortoise_i == tortoise_period) {
|
|
||||||
tortoise[0] = dir.tail[0];
|
|
||||||
tortoise[1] = dir.tail[1];
|
|
||||||
tortoise_i = 0;
|
|
||||||
tortoise_period *= 2;
|
|
||||||
}
|
|
||||||
tortoise_i += 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
int err = cb(data, dir.tail[i]);
|
int err = cb(data, dir.tail[i]);
|
||||||
@@ -4727,22 +4800,17 @@ static int lfs_fs_pred(lfs_t *lfs,
|
|||||||
// iterate over all directory directory entries
|
// iterate over all directory directory entries
|
||||||
pdir->tail[0] = 0;
|
pdir->tail[0] = 0;
|
||||||
pdir->tail[1] = 1;
|
pdir->tail[1] = 1;
|
||||||
lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
|
struct lfs_tortoise_t tortoise = {
|
||||||
lfs_size_t tortoise_i = 1;
|
.pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
|
||||||
lfs_size_t tortoise_period = 1;
|
.i = 1,
|
||||||
|
.period = 1,
|
||||||
|
};
|
||||||
|
int err = LFS_ERR_OK;
|
||||||
while (!lfs_pair_isnull(pdir->tail)) {
|
while (!lfs_pair_isnull(pdir->tail)) {
|
||||||
// detect cycles with Brent's algorithm
|
err = lfs_tortoise_detectcycles(pdir, &tortoise);
|
||||||
if (lfs_pair_issync(pdir->tail, tortoise)) {
|
if (err < 0) {
|
||||||
LFS_WARN("Cycle detected in tail list");
|
|
||||||
return LFS_ERR_CORRUPT;
|
return LFS_ERR_CORRUPT;
|
||||||
}
|
}
|
||||||
if (tortoise_i == tortoise_period) {
|
|
||||||
tortoise[0] = pdir->tail[0];
|
|
||||||
tortoise[1] = pdir->tail[1];
|
|
||||||
tortoise_i = 0;
|
|
||||||
tortoise_period *= 2;
|
|
||||||
}
|
|
||||||
tortoise_i += 1;
|
|
||||||
|
|
||||||
if (lfs_pair_cmp(pdir->tail, pair) == 0) {
|
if (lfs_pair_cmp(pdir->tail, pair) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4792,22 +4860,17 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
|||||||
// use fetchmatch with callback to find pairs
|
// use fetchmatch with callback to find pairs
|
||||||
parent->tail[0] = 0;
|
parent->tail[0] = 0;
|
||||||
parent->tail[1] = 1;
|
parent->tail[1] = 1;
|
||||||
lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
|
struct lfs_tortoise_t tortoise = {
|
||||||
lfs_size_t tortoise_i = 1;
|
.pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
|
||||||
lfs_size_t tortoise_period = 1;
|
.i = 1,
|
||||||
|
.period = 1,
|
||||||
|
};
|
||||||
|
int err = LFS_ERR_OK;
|
||||||
while (!lfs_pair_isnull(parent->tail)) {
|
while (!lfs_pair_isnull(parent->tail)) {
|
||||||
// detect cycles with Brent's algorithm
|
err = lfs_tortoise_detectcycles(parent, &tortoise);
|
||||||
if (lfs_pair_issync(parent->tail, tortoise)) {
|
if (err < 0) {
|
||||||
LFS_WARN("Cycle detected in tail list");
|
return err;
|
||||||
return LFS_ERR_CORRUPT;
|
|
||||||
}
|
}
|
||||||
if (tortoise_i == tortoise_period) {
|
|
||||||
tortoise[0] = parent->tail[0];
|
|
||||||
tortoise[1] = parent->tail[1];
|
|
||||||
tortoise_i = 0;
|
|
||||||
tortoise_period *= 2;
|
|
||||||
}
|
|
||||||
tortoise_i += 1;
|
|
||||||
|
|
||||||
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail,
|
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail,
|
||||||
LFS_MKTAG(0x7ff, 0, 0x3ff),
|
LFS_MKTAG(0x7ff, 0, 0x3ff),
|
||||||
@@ -5890,7 +5953,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||||
".block_size=%"PRIu32", .block_count=%"PRIu32", "
|
".block_size=%"PRIu32", .block_count=%"PRIu32", "
|
||||||
".block_cycles=%"PRIu32", .cache_size=%"PRIu32", "
|
".block_cycles=%"PRId32", .cache_size=%"PRIu32", "
|
||||||
".lookahead_size=%"PRIu32", .read_buffer=%p, "
|
".lookahead_size=%"PRIu32", .read_buffer=%p, "
|
||||||
".prog_buffer=%p, .lookahead_buffer=%p, "
|
".prog_buffer=%p, .lookahead_buffer=%p, "
|
||||||
".name_max=%"PRIu32", .file_max=%"PRIu32", "
|
".name_max=%"PRIu32", .file_max=%"PRIu32", "
|
||||||
@@ -5920,7 +5983,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||||
".block_size=%"PRIu32", .block_count=%"PRIu32", "
|
".block_size=%"PRIu32", .block_count=%"PRIu32", "
|
||||||
".block_cycles=%"PRIu32", .cache_size=%"PRIu32", "
|
".block_cycles=%"PRId32", .cache_size=%"PRIu32", "
|
||||||
".lookahead_size=%"PRIu32", .read_buffer=%p, "
|
".lookahead_size=%"PRIu32", .read_buffer=%p, "
|
||||||
".prog_buffer=%p, .lookahead_buffer=%p, "
|
".prog_buffer=%p, .lookahead_buffer=%p, "
|
||||||
".name_max=%"PRIu32", .file_max=%"PRIu32", "
|
".name_max=%"PRIu32", .file_max=%"PRIu32", "
|
||||||
@@ -6057,7 +6120,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)",
|
LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)",
|
||||||
(void*)lfs, (void*)file, path, flags);
|
(void*)lfs, (void*)file, path, (unsigned)flags);
|
||||||
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
err = lfs_file_open_(lfs, file, path, flags);
|
err = lfs_file_open_(lfs, file, path, flags);
|
||||||
@@ -6077,7 +6140,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {"
|
LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {"
|
||||||
".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})",
|
".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})",
|
||||||
(void*)lfs, (void*)file, path, flags,
|
(void*)lfs, (void*)file, path, (unsigned)flags,
|
||||||
(void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count);
|
(void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count);
|
||||||
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
@@ -6439,7 +6502,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
".read=%p, .prog=%p, .erase=%p, .sync=%p, "
|
||||||
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
".read_size=%"PRIu32", .prog_size=%"PRIu32", "
|
||||||
".block_size=%"PRIu32", .block_count=%"PRIu32", "
|
".block_size=%"PRIu32", .block_count=%"PRIu32", "
|
||||||
".block_cycles=%"PRIu32", .cache_size=%"PRIu32", "
|
".block_cycles=%"PRId32", .cache_size=%"PRIu32", "
|
||||||
".lookahead_size=%"PRIu32", .read_buffer=%p, "
|
".lookahead_size=%"PRIu32", .read_buffer=%p, "
|
||||||
".prog_buffer=%p, .lookahead_buffer=%p, "
|
".prog_buffer=%p, .lookahead_buffer=%p, "
|
||||||
".name_max=%"PRIu32", .file_max=%"PRIu32", "
|
".name_max=%"PRIu32", .file_max=%"PRIu32", "
|
||||||
|
|||||||
2
lfs.h
2
lfs.h
@@ -21,7 +21,7 @@ extern "C"
|
|||||||
// Software library version
|
// Software library version
|
||||||
// Major (top-nibble), incremented on backwards incompatible changes
|
// Major (top-nibble), incremented on backwards incompatible changes
|
||||||
// Minor (bottom-nibble), incremented on feature additions
|
// Minor (bottom-nibble), incremented on feature additions
|
||||||
#define LFS_VERSION 0x00020009
|
#define LFS_VERSION 0x0002000a
|
||||||
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
|
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
|
||||||
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
|
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
|
||||||
|
|
||||||
|
|||||||
22
lfs_util.h
22
lfs_util.h
@@ -8,6 +8,9 @@
|
|||||||
#ifndef LFS_UTIL_H
|
#ifndef LFS_UTIL_H
|
||||||
#define LFS_UTIL_H
|
#define LFS_UTIL_H
|
||||||
|
|
||||||
|
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
|
||||||
|
#define LFS_STRINGIZE2(x) #x
|
||||||
|
|
||||||
// Users can override lfs_util.h with their own configuration by defining
|
// Users can override lfs_util.h with their own configuration by defining
|
||||||
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
|
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
|
||||||
//
|
//
|
||||||
@@ -15,11 +18,26 @@
|
|||||||
// provided by the config file. To start, I would suggest copying lfs_util.h
|
// provided by the config file. To start, I would suggest copying lfs_util.h
|
||||||
// and modifying as needed.
|
// and modifying as needed.
|
||||||
#ifdef LFS_CONFIG
|
#ifdef LFS_CONFIG
|
||||||
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
|
|
||||||
#define LFS_STRINGIZE2(x) #x
|
|
||||||
#include LFS_STRINGIZE(LFS_CONFIG)
|
#include LFS_STRINGIZE(LFS_CONFIG)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
// Alternatively, users can provide a header file which defines
|
||||||
|
// macros and other things consumed by littlefs.
|
||||||
|
//
|
||||||
|
// For example, provide my_defines.h, which contains
|
||||||
|
// something like:
|
||||||
|
//
|
||||||
|
// #include <stddef.h>
|
||||||
|
// extern void *my_malloc(size_t sz);
|
||||||
|
// #define LFS_MALLOC(sz) my_malloc(sz)
|
||||||
|
//
|
||||||
|
// And build littlefs with the header by defining LFS_DEFINES.
|
||||||
|
// (-DLFS_DEFINES=my_defines.h)
|
||||||
|
|
||||||
|
#ifdef LFS_DEFINES
|
||||||
|
#include LFS_STRINGIZE(LFS_DEFINES)
|
||||||
|
#endif
|
||||||
|
|
||||||
// System includes
|
// System includes
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|||||||
@@ -1322,6 +1322,7 @@ void perm_run(
|
|||||||
.cache_size = CACHE_SIZE,
|
.cache_size = CACHE_SIZE,
|
||||||
.lookahead_size = LOOKAHEAD_SIZE,
|
.lookahead_size = LOOKAHEAD_SIZE,
|
||||||
.compact_thresh = COMPACT_THRESH,
|
.compact_thresh = COMPACT_THRESH,
|
||||||
|
.metadata_max = METADATA_MAX,
|
||||||
.inline_max = INLINE_MAX,
|
.inline_max = INLINE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -96,12 +96,13 @@ intmax_t bench_define(size_t define);
|
|||||||
#define CACHE_SIZE_i 6
|
#define CACHE_SIZE_i 6
|
||||||
#define LOOKAHEAD_SIZE_i 7
|
#define LOOKAHEAD_SIZE_i 7
|
||||||
#define COMPACT_THRESH_i 8
|
#define COMPACT_THRESH_i 8
|
||||||
#define INLINE_MAX_i 9
|
#define METADATA_MAX_i 9
|
||||||
#define BLOCK_CYCLES_i 10
|
#define INLINE_MAX_i 10
|
||||||
#define ERASE_VALUE_i 11
|
#define BLOCK_CYCLES_i 11
|
||||||
#define ERASE_CYCLES_i 12
|
#define ERASE_VALUE_i 12
|
||||||
#define BADBLOCK_BEHAVIOR_i 13
|
#define ERASE_CYCLES_i 13
|
||||||
#define POWERLOSS_BEHAVIOR_i 14
|
#define BADBLOCK_BEHAVIOR_i 14
|
||||||
|
#define POWERLOSS_BEHAVIOR_i 15
|
||||||
|
|
||||||
#define READ_SIZE bench_define(READ_SIZE_i)
|
#define READ_SIZE bench_define(READ_SIZE_i)
|
||||||
#define PROG_SIZE bench_define(PROG_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 CACHE_SIZE bench_define(CACHE_SIZE_i)
|
||||||
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
|
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
|
||||||
#define COMPACT_THRESH bench_define(COMPACT_THRESH_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 INLINE_MAX bench_define(INLINE_MAX_i)
|
||||||
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
|
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
|
||||||
#define ERASE_VALUE bench_define(ERASE_VALUE_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(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
|
||||||
BENCH_DEF(LOOKAHEAD_SIZE, 16) \
|
BENCH_DEF(LOOKAHEAD_SIZE, 16) \
|
||||||
BENCH_DEF(COMPACT_THRESH, 0) \
|
BENCH_DEF(COMPACT_THRESH, 0) \
|
||||||
|
BENCH_DEF(METADATA_MAX, 0) \
|
||||||
BENCH_DEF(INLINE_MAX, 0) \
|
BENCH_DEF(INLINE_MAX, 0) \
|
||||||
BENCH_DEF(BLOCK_CYCLES, -1) \
|
BENCH_DEF(BLOCK_CYCLES, -1) \
|
||||||
BENCH_DEF(ERASE_VALUE, 0xff) \
|
BENCH_DEF(ERASE_VALUE, 0xff) \
|
||||||
@@ -137,7 +140,7 @@ intmax_t bench_define(size_t define);
|
|||||||
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
|
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
|
||||||
|
|
||||||
#define BENCH_GEOMETRY_DEFINE_COUNT 4
|
#define BENCH_GEOMETRY_DEFINE_COUNT 4
|
||||||
#define BENCH_IMPLICIT_DEFINE_COUNT 15
|
#define BENCH_IMPLICIT_DEFINE_COUNT 16
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1347,6 +1347,7 @@ static void run_powerloss_none(
|
|||||||
.cache_size = CACHE_SIZE,
|
.cache_size = CACHE_SIZE,
|
||||||
.lookahead_size = LOOKAHEAD_SIZE,
|
.lookahead_size = LOOKAHEAD_SIZE,
|
||||||
.compact_thresh = COMPACT_THRESH,
|
.compact_thresh = COMPACT_THRESH,
|
||||||
|
.metadata_max = METADATA_MAX,
|
||||||
.inline_max = INLINE_MAX,
|
.inline_max = INLINE_MAX,
|
||||||
#ifdef LFS_MULTIVERSION
|
#ifdef LFS_MULTIVERSION
|
||||||
.disk_version = DISK_VERSION,
|
.disk_version = DISK_VERSION,
|
||||||
@@ -1425,6 +1426,7 @@ static void run_powerloss_linear(
|
|||||||
.cache_size = CACHE_SIZE,
|
.cache_size = CACHE_SIZE,
|
||||||
.lookahead_size = LOOKAHEAD_SIZE,
|
.lookahead_size = LOOKAHEAD_SIZE,
|
||||||
.compact_thresh = COMPACT_THRESH,
|
.compact_thresh = COMPACT_THRESH,
|
||||||
|
.metadata_max = METADATA_MAX,
|
||||||
.inline_max = INLINE_MAX,
|
.inline_max = INLINE_MAX,
|
||||||
#ifdef LFS_MULTIVERSION
|
#ifdef LFS_MULTIVERSION
|
||||||
.disk_version = DISK_VERSION,
|
.disk_version = DISK_VERSION,
|
||||||
@@ -1520,6 +1522,7 @@ static void run_powerloss_log(
|
|||||||
.cache_size = CACHE_SIZE,
|
.cache_size = CACHE_SIZE,
|
||||||
.lookahead_size = LOOKAHEAD_SIZE,
|
.lookahead_size = LOOKAHEAD_SIZE,
|
||||||
.compact_thresh = COMPACT_THRESH,
|
.compact_thresh = COMPACT_THRESH,
|
||||||
|
.metadata_max = METADATA_MAX,
|
||||||
.inline_max = INLINE_MAX,
|
.inline_max = INLINE_MAX,
|
||||||
#ifdef LFS_MULTIVERSION
|
#ifdef LFS_MULTIVERSION
|
||||||
.disk_version = DISK_VERSION,
|
.disk_version = DISK_VERSION,
|
||||||
@@ -1613,6 +1616,7 @@ static void run_powerloss_cycles(
|
|||||||
.cache_size = CACHE_SIZE,
|
.cache_size = CACHE_SIZE,
|
||||||
.lookahead_size = LOOKAHEAD_SIZE,
|
.lookahead_size = LOOKAHEAD_SIZE,
|
||||||
.compact_thresh = COMPACT_THRESH,
|
.compact_thresh = COMPACT_THRESH,
|
||||||
|
.metadata_max = METADATA_MAX,
|
||||||
.inline_max = INLINE_MAX,
|
.inline_max = INLINE_MAX,
|
||||||
#ifdef LFS_MULTIVERSION
|
#ifdef LFS_MULTIVERSION
|
||||||
.disk_version = DISK_VERSION,
|
.disk_version = DISK_VERSION,
|
||||||
@@ -1804,6 +1808,7 @@ static void run_powerloss_exhaustive(
|
|||||||
.cache_size = CACHE_SIZE,
|
.cache_size = CACHE_SIZE,
|
||||||
.lookahead_size = LOOKAHEAD_SIZE,
|
.lookahead_size = LOOKAHEAD_SIZE,
|
||||||
.compact_thresh = COMPACT_THRESH,
|
.compact_thresh = COMPACT_THRESH,
|
||||||
|
.metadata_max = METADATA_MAX,
|
||||||
.inline_max = INLINE_MAX,
|
.inline_max = INLINE_MAX,
|
||||||
#ifdef LFS_MULTIVERSION
|
#ifdef LFS_MULTIVERSION
|
||||||
.disk_version = DISK_VERSION,
|
.disk_version = DISK_VERSION,
|
||||||
|
|||||||
@@ -89,13 +89,14 @@ intmax_t test_define(size_t define);
|
|||||||
#define CACHE_SIZE_i 6
|
#define CACHE_SIZE_i 6
|
||||||
#define LOOKAHEAD_SIZE_i 7
|
#define LOOKAHEAD_SIZE_i 7
|
||||||
#define COMPACT_THRESH_i 8
|
#define COMPACT_THRESH_i 8
|
||||||
#define INLINE_MAX_i 9
|
#define METADATA_MAX_i 9
|
||||||
#define BLOCK_CYCLES_i 10
|
#define INLINE_MAX_i 10
|
||||||
#define ERASE_VALUE_i 11
|
#define BLOCK_CYCLES_i 11
|
||||||
#define ERASE_CYCLES_i 12
|
#define ERASE_VALUE_i 12
|
||||||
#define BADBLOCK_BEHAVIOR_i 13
|
#define ERASE_CYCLES_i 13
|
||||||
#define POWERLOSS_BEHAVIOR_i 14
|
#define BADBLOCK_BEHAVIOR_i 14
|
||||||
#define DISK_VERSION_i 15
|
#define POWERLOSS_BEHAVIOR_i 15
|
||||||
|
#define DISK_VERSION_i 16
|
||||||
|
|
||||||
#define READ_SIZE TEST_DEFINE(READ_SIZE_i)
|
#define READ_SIZE TEST_DEFINE(READ_SIZE_i)
|
||||||
#define PROG_SIZE TEST_DEFINE(PROG_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 CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i)
|
||||||
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
|
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
|
||||||
#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_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 INLINE_MAX TEST_DEFINE(INLINE_MAX_i)
|
||||||
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
|
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
|
||||||
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_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(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
|
||||||
TEST_DEF(LOOKAHEAD_SIZE, 16) \
|
TEST_DEF(LOOKAHEAD_SIZE, 16) \
|
||||||
TEST_DEF(COMPACT_THRESH, 0) \
|
TEST_DEF(COMPACT_THRESH, 0) \
|
||||||
|
TEST_DEF(METADATA_MAX, 0) \
|
||||||
TEST_DEF(INLINE_MAX, 0) \
|
TEST_DEF(INLINE_MAX, 0) \
|
||||||
TEST_DEF(BLOCK_CYCLES, -1) \
|
TEST_DEF(BLOCK_CYCLES, -1) \
|
||||||
TEST_DEF(ERASE_VALUE, 0xff) \
|
TEST_DEF(ERASE_VALUE, 0xff) \
|
||||||
@@ -133,7 +136,7 @@ intmax_t test_define(size_t define);
|
|||||||
TEST_DEF(DISK_VERSION, 0)
|
TEST_DEF(DISK_VERSION, 0)
|
||||||
|
|
||||||
#define TEST_GEOMETRY_DEFINE_COUNT 4
|
#define TEST_GEOMETRY_DEFINE_COUNT 4
|
||||||
#define TEST_IMPLICIT_DEFINE_COUNT 16
|
#define TEST_IMPLICIT_DEFINE_COUNT 17
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -86,6 +86,13 @@ def write_header(f, limit=LIMIT):
|
|||||||
f.writeln("}")
|
f.writeln("}")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln("__attribute__((unused))")
|
f.writeln("__attribute__((unused))")
|
||||||
|
f.writeln("static void __pretty_assert_print_ptr(")
|
||||||
|
f.writeln(" const void *v, size_t size) {")
|
||||||
|
f.writeln(" (void)size;")
|
||||||
|
f.writeln(" printf(\"%p\", v);")
|
||||||
|
f.writeln("}")
|
||||||
|
f.writeln()
|
||||||
|
f.writeln("__attribute__((unused))")
|
||||||
f.writeln("static void __pretty_assert_print_mem(")
|
f.writeln("static void __pretty_assert_print_mem(")
|
||||||
f.writeln(" const void *v, size_t size) {")
|
f.writeln(" const void *v, size_t size) {")
|
||||||
f.writeln(" const uint8_t *v_ = v;")
|
f.writeln(" const uint8_t *v_ = v;")
|
||||||
@@ -183,6 +190,23 @@ def write_header(f, limit=LIMIT):
|
|||||||
f.writeln(" _rh, strlen(_rh)); \\")
|
f.writeln(" _rh, strlen(_rh)); \\")
|
||||||
f.writeln(" } \\")
|
f.writeln(" } \\")
|
||||||
f.writeln("} while (0)")
|
f.writeln("} while (0)")
|
||||||
|
for op, cmp in sorted(CMP.items()):
|
||||||
|
# Only EQ and NE are supported when compared to NULL.
|
||||||
|
if cmp not in ['eq', 'ne']:
|
||||||
|
continue
|
||||||
|
f.writeln("#define __PRETTY_ASSERT_PTR_%s(lh, rh) do { \\"
|
||||||
|
% cmp.upper())
|
||||||
|
f.writeln(" const void *_lh = (const void*)(uintptr_t)lh; \\")
|
||||||
|
f.writeln(" const void *_rh = (const void*)(uintptr_t)rh; \\")
|
||||||
|
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
||||||
|
f.writeln(" __pretty_assert_fail( \\")
|
||||||
|
f.writeln(" __FILE__, __LINE__, \\")
|
||||||
|
f.writeln(" __pretty_assert_print_ptr, \"%s\", \\"
|
||||||
|
% cmp)
|
||||||
|
f.writeln(" (const void*){_lh}, 0, \\")
|
||||||
|
f.writeln(" (const void*){_rh}, 0); \\")
|
||||||
|
f.writeln(" } \\")
|
||||||
|
f.writeln("} while (0)")
|
||||||
f.writeln()
|
f.writeln()
|
||||||
f.writeln()
|
f.writeln()
|
||||||
|
|
||||||
@@ -301,6 +325,8 @@ def p_assert(p):
|
|||||||
cmp = p.expect('cmp') ; p.accept('ws')
|
cmp = p.expect('cmp') ; p.accept('ws')
|
||||||
rh = p_expr(p) ; p.accept('ws')
|
rh = p_expr(p) ; p.accept('ws')
|
||||||
p.expect(')')
|
p.expect(')')
|
||||||
|
if rh == 'NULL' or lh == 'NULL':
|
||||||
|
return mkassert('ptr', CMP[cmp], lh, rh)
|
||||||
return mkassert('int', CMP[cmp], lh, rh)
|
return mkassert('int', CMP[cmp], lh, rh)
|
||||||
except ParseFailure:
|
except ParseFailure:
|
||||||
p.pop(state)
|
p.pop(state)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -405,3 +405,111 @@ code = '''
|
|||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
# test possible overflow/underflow conditions
|
||||||
|
#
|
||||||
|
# note these need -fsanitize=undefined to consistently detect
|
||||||
|
# overflow/underflow conditions
|
||||||
|
|
||||||
|
[cases.test_seek_filemax]
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_format(&lfs, cfg) => 0;
|
||||||
|
lfs_mount(&lfs, cfg) => 0;
|
||||||
|
lfs_file_t file;
|
||||||
|
lfs_file_open(&lfs, &file, "kitty",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
strcpy((char*)buffer, "kittycatcat");
|
||||||
|
size_t size = strlen((char*)buffer);
|
||||||
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||||
|
|
||||||
|
// seek with LFS_SEEK_SET
|
||||||
|
lfs_file_seek(&lfs, &file, LFS_FILE_MAX, LFS_SEEK_SET) => LFS_FILE_MAX;
|
||||||
|
|
||||||
|
// seek with LFS_SEEK_CUR
|
||||||
|
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => LFS_FILE_MAX;
|
||||||
|
|
||||||
|
// the file hasn't changed size, so seek end takes us back to the offset=0
|
||||||
|
lfs_file_seek(&lfs, &file, +10, LFS_SEEK_END) => size+10;
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_seek_underflow]
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_format(&lfs, cfg) => 0;
|
||||||
|
lfs_mount(&lfs, cfg) => 0;
|
||||||
|
lfs_file_t file;
|
||||||
|
lfs_file_open(&lfs, &file, "kitty",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
strcpy((char*)buffer, "kittycatcat");
|
||||||
|
size_t size = strlen((char*)buffer);
|
||||||
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||||
|
|
||||||
|
// underflow with LFS_SEEK_CUR, should error
|
||||||
|
lfs_file_seek(&lfs, &file, -(size+10), LFS_SEEK_CUR) => LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file, -LFS_FILE_MAX, LFS_SEEK_CUR) => LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file, -(size+LFS_FILE_MAX), LFS_SEEK_CUR)
|
||||||
|
=> LFS_ERR_INVAL;
|
||||||
|
|
||||||
|
// underflow with LFS_SEEK_END, should error
|
||||||
|
lfs_file_seek(&lfs, &file, -(size+10), LFS_SEEK_END) => LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file, -LFS_FILE_MAX, LFS_SEEK_END) => LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file, -(size+LFS_FILE_MAX), LFS_SEEK_END)
|
||||||
|
=> LFS_ERR_INVAL;
|
||||||
|
|
||||||
|
// file pointer should not have changed
|
||||||
|
lfs_file_tell(&lfs, &file) => size;
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_seek_overflow]
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_format(&lfs, cfg) => 0;
|
||||||
|
lfs_mount(&lfs, cfg) => 0;
|
||||||
|
lfs_file_t file;
|
||||||
|
lfs_file_open(&lfs, &file, "kitty",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
strcpy((char*)buffer, "kittycatcat");
|
||||||
|
size_t size = strlen((char*)buffer);
|
||||||
|
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||||
|
|
||||||
|
// seek to LFS_FILE_MAX
|
||||||
|
lfs_file_seek(&lfs, &file, LFS_FILE_MAX, LFS_SEEK_SET) => LFS_FILE_MAX;
|
||||||
|
|
||||||
|
// overflow with LFS_SEEK_CUR, should error
|
||||||
|
lfs_file_seek(&lfs, &file, +10, LFS_SEEK_CUR) => LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file, +LFS_FILE_MAX, LFS_SEEK_CUR) => LFS_ERR_INVAL;
|
||||||
|
|
||||||
|
// LFS_SEEK_SET/END don't care about the current file position, but we can
|
||||||
|
// still overflow with a large offset
|
||||||
|
|
||||||
|
// overflow with LFS_SEEK_SET, should error
|
||||||
|
lfs_file_seek(&lfs, &file,
|
||||||
|
+((uint32_t)LFS_FILE_MAX+10),
|
||||||
|
LFS_SEEK_SET) => LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file,
|
||||||
|
+((uint32_t)LFS_FILE_MAX+(uint32_t)LFS_FILE_MAX),
|
||||||
|
LFS_SEEK_SET) => LFS_ERR_INVAL;
|
||||||
|
|
||||||
|
// overflow with LFS_SEEK_END, should error
|
||||||
|
lfs_file_seek(&lfs, &file, +(LFS_FILE_MAX-size+10), LFS_SEEK_END)
|
||||||
|
=> LFS_ERR_INVAL;
|
||||||
|
lfs_file_seek(&lfs, &file, +(LFS_FILE_MAX-size+LFS_FILE_MAX), LFS_SEEK_END)
|
||||||
|
=> LFS_ERR_INVAL;
|
||||||
|
|
||||||
|
// file pointer should not have changed
|
||||||
|
lfs_file_tell(&lfs, &file) => LFS_FILE_MAX;
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|||||||
@@ -523,3 +523,30 @@ code = '''
|
|||||||
assert(memcmp(buffer, "hello!", 6) == 0);
|
assert(memcmp(buffer, "hello!", 6) == 0);
|
||||||
lfs_unmount(&lfs) => 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;
|
||||||
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user