mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into debug-improvements
This commit is contained in:
		
							
								
								
									
										16
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -23,8 +23,20 @@ script: | |||||||
|   - make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" |   - make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" | ||||||
|  |  | ||||||
|   - make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0" |   - make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0" | ||||||
|  |   - make clean test QUIET=1 CFLAGS+="-DLFS_EMUBD_ERASE_VALUE=0xff" | ||||||
|   - make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS" |   - make clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS" | ||||||
|  |  | ||||||
|  |   # additional configurations that don't support all tests (this should be | ||||||
|  |   # fixed but at the moment it is what it is) | ||||||
|  |   - make test_files QUIET=1 | ||||||
|  |         CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096" | ||||||
|  |   - make test_files QUIET=1 | ||||||
|  |         CFLAGS+="-DLFS_READ_SIZE=\(2*1024\) -DLFS_BLOCK_SIZE=\(64*1024\)" | ||||||
|  |   - make test_files QUIET=1 | ||||||
|  |         CFLAGS+="-DLFS_READ_SIZE=\(8*1024\) -DLFS_BLOCK_SIZE=\(64*1024\)" | ||||||
|  |   - make test_files QUIET=1 | ||||||
|  |         CFLAGS+="-DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704" | ||||||
|  |  | ||||||
|   # compile and find the code size with the smallest configuration |   # compile and find the code size with the smallest configuration | ||||||
|   - make clean size |   - make clean size | ||||||
|         OBJ="$(ls lfs*.o | tr '\n' ' ')" |         OBJ="$(ls lfs*.o | tr '\n' ' ')" | ||||||
| @@ -111,7 +123,7 @@ jobs: | |||||||
|       if: branch !~ -prefix$ |       if: branch !~ -prefix$ | ||||||
|       install: |       install: | ||||||
|         - sudo apt-get install libfuse-dev |         - sudo apt-get install libfuse-dev | ||||||
|         - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2-alpha |         - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 | ||||||
|         - fusermount -V |         - fusermount -V | ||||||
|         - gcc --version |         - gcc --version | ||||||
|       before_script: |       before_script: | ||||||
| @@ -146,7 +158,7 @@ jobs: | |||||||
|       if: branch !~ -prefix$ |       if: branch !~ -prefix$ | ||||||
|       install: |       install: | ||||||
|         - sudo apt-get install libfuse-dev |         - sudo apt-get install libfuse-dev | ||||||
|         - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2-alpha v2 |         - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2 | ||||||
|         - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1 |         - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1 | ||||||
|         - fusermount -V |         - fusermount -V | ||||||
|         - gcc --version |         - gcc --version | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -60,7 +60,7 @@ test: \ | |||||||
| test_%: tests/test_%.sh | test_%: tests/test_%.sh | ||||||
|  |  | ||||||
| ifdef QUIET | ifdef QUIET | ||||||
| 	@./$< | sed -n '/^[-=]/p' | 	@./$< | sed -nu '/^[-=]/p' | ||||||
| else | else | ||||||
| 	./$< | 	./$< | ||||||
| endif | endif | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
| #include <dirent.h> |  | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| @@ -96,7 +95,7 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { | |||||||
|     snprintf(emu->child, LFS_NAME_MAX, ".stats"); |     snprintf(emu->child, LFS_NAME_MAX, ".stats"); | ||||||
|     FILE *f = fopen(emu->path, "r"); |     FILE *f = fopen(emu->path, "r"); | ||||||
|     if (!f) { |     if (!f) { | ||||||
|         memset(&emu->stats, 0, sizeof(emu->stats)); |         memset(&emu->stats, LFS_EMUBD_ERASE_VALUE, sizeof(emu->stats)); | ||||||
|     } else { |     } else { | ||||||
|         size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f); |         size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f); | ||||||
|         lfs_emubd_fromle32(emu); |         lfs_emubd_fromle32(emu); | ||||||
| @@ -265,7 +264,7 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, | |||||||
|  |  | ||||||
|     // update history and stats |     // update history and stats | ||||||
|     if (block != emu->history.blocks[0]) { |     if (block != emu->history.blocks[0]) { | ||||||
|         memcpy(&emu->history.blocks[1], &emu->history.blocks[0], |         memmove(&emu->history.blocks[1], &emu->history.blocks[0], | ||||||
|                 sizeof(emu->history) - sizeof(emu->history.blocks[0])); |                 sizeof(emu->history) - sizeof(emu->history.blocks[0])); | ||||||
|         emu->history.blocks[0] = block; |         emu->history.blocks[0] = block; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -17,20 +17,8 @@ extern "C" | |||||||
|  |  | ||||||
|  |  | ||||||
| // Config options | // Config options | ||||||
| #ifndef LFS_EMUBD_READ_SIZE | #ifndef LFS_EMUBD_ERASE_VALUE | ||||||
| #define LFS_EMUBD_READ_SIZE 1 | #define LFS_EMUBD_ERASE_VALUE 0x00 | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_EMUBD_PROG_SIZE |  | ||||||
| #define LFS_EMUBD_PROG_SIZE 1 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_EMUBD_ERASE_SIZE |  | ||||||
| #define LFS_EMUBD_ERASE_SIZE 512 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_EMUBD_TOTAL_SIZE |  | ||||||
| #define LFS_EMUBD_TOTAL_SIZE 524288 |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										221
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -1,19 +1,8 @@ | |||||||
| /* | /* | ||||||
|  * The little filesystem |  * The little filesystem | ||||||
|  * |  * | ||||||
|  * Copyright (c) 2017 ARM Limited |  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||||
|  * |  * SPDX-License-Identifier: BSD-3-Clause | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
|  * you may not use this file except in compliance with the License. |  | ||||||
|  * You may obtain a copy of the License at |  | ||||||
|  * |  | ||||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
|  * |  | ||||||
|  * Unless required by applicable law or agreed to in writing, software |  | ||||||
|  * distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|  * See the License for the specific language governing permissions and |  | ||||||
|  * limitations under the License. |  | ||||||
|  */ |  */ | ||||||
| #include "lfs.h" | #include "lfs.h" | ||||||
| #include "lfs_util.h" | #include "lfs_util.h" | ||||||
| @@ -420,7 +409,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
| static int lfs_dir_compact(lfs_t *lfs, | static int lfs_dir_compact(lfs_t *lfs, | ||||||
|         lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, |         lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, | ||||||
|         lfs_mdir_t *source, uint16_t begin, uint16_t end); |         lfs_mdir_t *source, uint16_t begin, uint16_t end); | ||||||
| static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file); | static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); | ||||||
| static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); | static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); | ||||||
| static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); | static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); | ||||||
| static void lfs_fs_prepmove(lfs_t *lfs, | static void lfs_fs_prepmove(lfs_t *lfs, | ||||||
| @@ -636,11 +625,17 @@ static int lfs_dir_traverse_filter(void *p, | |||||||
|     lfs_tag_t *filtertag = p; |     lfs_tag_t *filtertag = p; | ||||||
|     (void)buffer; |     (void)buffer; | ||||||
|  |  | ||||||
|  |     // which mask depends on unique bit in tag structure | ||||||
|  |     uint32_t mask = (tag & LFS_MKTAG(0x100, 0, 0)) | ||||||
|  |             ? LFS_MKTAG(0x7ff, 0x3ff, 0) | ||||||
|  |             : LFS_MKTAG(0x700, 0x3ff, 0); | ||||||
|  |  | ||||||
|     // check for redundancy |     // check for redundancy | ||||||
|     uint32_t mask = LFS_MKTAG(0x7ff, 0x3ff, 0); |  | ||||||
|     if ((mask & tag) == (mask & *filtertag) || |     if ((mask & tag) == (mask & *filtertag) || | ||||||
|         (mask & tag) == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | |             lfs_tag_isdelete(*filtertag) || | ||||||
|             (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { |             (LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == ( | ||||||
|  |                 LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | | ||||||
|  |                     (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1238,65 +1233,85 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, | |||||||
|  |  | ||||||
| static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | ||||||
|     // align to program units |     // align to program units | ||||||
|     lfs_off_t off = lfs_alignup(commit->off + 2*sizeof(uint32_t), |     const lfs_off_t off1 = commit->off + sizeof(lfs_tag_t); | ||||||
|  |     const lfs_off_t end = lfs_alignup(off1 + sizeof(uint32_t), | ||||||
|             lfs->cfg->prog_size); |             lfs->cfg->prog_size); | ||||||
|  |  | ||||||
|     // read erased state from next program unit |     // create crc tags to fill up remainder of commit, note that | ||||||
|     lfs_tag_t tag; |     // padding is not crcd, which lets fetches skip padding but | ||||||
|     int err = lfs_bd_read(lfs, |     // makes committing a bit more complicated | ||||||
|             NULL, &lfs->rcache, sizeof(tag), |     while (commit->off < end) { | ||||||
|             commit->block, off, &tag, sizeof(tag)); |         lfs_off_t off = commit->off + sizeof(lfs_tag_t); | ||||||
|     if (err && err != LFS_ERR_CORRUPT) { |         lfs_off_t noff = lfs_min(end - off, 0x3fe) + off; | ||||||
|         return err; |         if (noff < end) { | ||||||
|     } |             noff = lfs_min(noff, end - 2*sizeof(uint32_t)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|     // build crc tag |         // read erased state from next program unit | ||||||
|     bool reset = ~lfs_frombe32(tag) >> 31; |         lfs_tag_t tag = 0xffffffff; | ||||||
|     tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, |         int err = lfs_bd_read(lfs, | ||||||
|         off - (commit->off+sizeof(lfs_tag_t))); |                 NULL, &lfs->rcache, sizeof(tag), | ||||||
|  |                 commit->block, noff, &tag, sizeof(tag)); | ||||||
|  |         if (err && err != LFS_ERR_CORRUPT) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|     // write out crc |         // build crc tag | ||||||
|     uint32_t footer[2]; |         bool reset = ~lfs_frombe32(tag) >> 31; | ||||||
|     footer[0] = lfs_tobe32(tag ^ commit->ptag); |         tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, noff - off); | ||||||
|     commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0])); |  | ||||||
|     footer[1] = lfs_tole32(commit->crc); |  | ||||||
|     err = lfs_bd_prog(lfs, |  | ||||||
|             &lfs->pcache, &lfs->rcache, false, |  | ||||||
|             commit->block, commit->off, &footer, sizeof(footer)); |  | ||||||
|     if (err) { |  | ||||||
|         return err; |  | ||||||
|     } |  | ||||||
|     commit->off += sizeof(tag)+lfs_tag_size(tag); |  | ||||||
|     commit->ptag = tag ^ (reset << 31); |  | ||||||
|  |  | ||||||
|     // flush buffers |         // write out crc | ||||||
|     err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); |         uint32_t footer[2]; | ||||||
|     if (err) { |         footer[0] = lfs_tobe32(tag ^ commit->ptag); | ||||||
|         return err; |         commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0])); | ||||||
|     } |         footer[1] = lfs_tole32(commit->crc); | ||||||
|  |         err = lfs_bd_prog(lfs, | ||||||
|     // successful commit, check checksum to make sure |                 &lfs->pcache, &lfs->rcache, false, | ||||||
|     uint32_t crc = 0xffffffff; |                 commit->block, commit->off, &footer, sizeof(footer)); | ||||||
|     lfs_size_t size = commit->off - lfs_tag_size(tag) - commit->begin; |  | ||||||
|     for (lfs_off_t i = 0; i < size; i++) { |  | ||||||
|         // leave it up to caching to make this efficient |  | ||||||
|         uint8_t dat; |  | ||||||
|         err = lfs_bd_read(lfs, |  | ||||||
|                 NULL, &lfs->rcache, size-i, |  | ||||||
|                 commit->block, commit->begin+i, &dat, 1); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         crc = lfs_crc(crc, &dat, 1); |         commit->off += sizeof(tag)+lfs_tag_size(tag); | ||||||
|  |         commit->ptag = tag ^ (reset << 31); | ||||||
|  |         commit->crc = 0xffffffff; // reset crc for next "commit" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // flush buffers | ||||||
|  |     int err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (crc != commit->crc) { |     // successful commit, check checksums to make sure | ||||||
|         return LFS_ERR_CORRUPT; |     lfs_off_t off = commit->begin; | ||||||
|  |     lfs_off_t noff = off1; | ||||||
|  |     while (off < end) { | ||||||
|  |         uint32_t crc = 0xffffffff; | ||||||
|  |         for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { | ||||||
|  |             // leave it up to caching to make this efficient | ||||||
|  |             uint8_t dat; | ||||||
|  |             err = lfs_bd_read(lfs, | ||||||
|  |                     NULL, &lfs->rcache, noff+sizeof(uint32_t)-i, | ||||||
|  |                     commit->block, i, &dat, 1); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             crc = lfs_crc(crc, &dat, 1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // detected write error? | ||||||
|  |         if (crc != 0) { | ||||||
|  |             return LFS_ERR_CORRUPT; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // skip padding | ||||||
|  |         off = lfs_min(end - noff, 0x3fe) + noff; | ||||||
|  |         if (off < end) { | ||||||
|  |             off = lfs_min(off, end - 2*sizeof(uint32_t)); | ||||||
|  |         } | ||||||
|  |         noff = off + sizeof(uint32_t); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| @@ -1459,7 +1474,7 @@ static int lfs_dir_compact(lfs_t *lfs, | |||||||
|  |  | ||||||
|     // increment revision count |     // increment revision count | ||||||
|     dir->rev += 1; |     dir->rev += 1; | ||||||
|     if (lfs->cfg->block_cycles && |     if (lfs->cfg->block_cycles > 0 && | ||||||
|             (dir->rev % (lfs->cfg->block_cycles+1) == 0)) { |             (dir->rev % (lfs->cfg->block_cycles+1) == 0)) { | ||||||
|         if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { |         if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { | ||||||
|             // oh no! we're writing too much to the superblock, |             // oh no! we're writing too much to the superblock, | ||||||
| @@ -1589,11 +1604,11 @@ static int lfs_dir_compact(lfs_t *lfs, | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // successful compaction, swap dir pair to indicate most recent |             // successful compaction, swap dir pair to indicate most recent | ||||||
|  |             LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); | ||||||
|             lfs_pair_swap(dir->pair); |             lfs_pair_swap(dir->pair); | ||||||
|             dir->count = end - begin; |             dir->count = end - begin; | ||||||
|             dir->off = commit.off; |             dir->off = commit.off; | ||||||
|             dir->etag = commit.ptag; |             dir->etag = commit.ptag; | ||||||
|             dir->erased = (dir->off % lfs->cfg->prog_size == 0); |  | ||||||
|             // note we able to have already handled move here |             // note we able to have already handled move here | ||||||
|             if (lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) { |             if (lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) { | ||||||
|                 lfs_gstate_xormove(&lfs->gpending, |                 lfs_gstate_xormove(&lfs->gpending, | ||||||
| @@ -1649,11 +1664,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
|         if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && |         if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && | ||||||
|                 f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && |                 f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && | ||||||
|                 f->ctz.size > lfs->cfg->cache_size) { |                 f->ctz.size > lfs->cfg->cache_size) { | ||||||
|             f->flags &= ~LFS_F_READING; |             int err = lfs_file_outline(lfs, f); | ||||||
|             f->off = 0; |  | ||||||
|  |  | ||||||
|             lfs_alloc_ack(lfs); |  | ||||||
|             int err = lfs_file_relocate(lfs, f); |  | ||||||
|             if (err) { |             if (err) { | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
| @@ -1764,6 +1775,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // successful commit, update dir |         // successful commit, update dir | ||||||
|  |         LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); | ||||||
|         dir->off = commit.off; |         dir->off = commit.off; | ||||||
|         dir->etag = commit.ptag; |         dir->etag = commit.ptag; | ||||||
|  |  | ||||||
| @@ -2295,6 +2307,10 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|                  ".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, flags, | ||||||
|             (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); |             (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); | ||||||
|  |  | ||||||
|  |     // do not allow open for already opened file | ||||||
|  |     LFS_ASSERT(0 == (file->flags & LFS_F_OPENED)); | ||||||
|  |  | ||||||
|     // deorphan if we haven't yet, needed at most once after poweron |     // deorphan if we haven't yet, needed at most once after poweron | ||||||
|     if ((flags & 3) != LFS_O_RDONLY) { |     if ((flags & 3) != LFS_O_RDONLY) { | ||||||
|         int err = lfs_fs_forceconsistency(lfs); |         int err = lfs_fs_forceconsistency(lfs); | ||||||
| @@ -2307,7 +2323,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|     // setup simple file details |     // setup simple file details | ||||||
|     int err; |     int err; | ||||||
|     file->cfg = cfg; |     file->cfg = cfg; | ||||||
|     file->flags = flags; |     file->flags = flags | LFS_F_OPENED; | ||||||
|     file->pos = 0; |     file->pos = 0; | ||||||
|     file->cache.buffer = NULL; |     file->cache.buffer = NULL; | ||||||
|  |  | ||||||
| @@ -2452,6 +2468,8 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
|  |  | ||||||
| int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); |     LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |  | ||||||
|     int err = lfs_file_sync(lfs, file); |     int err = lfs_file_sync(lfs, file); | ||||||
|  |  | ||||||
|     // remove from list of mdirs |     // remove from list of mdirs | ||||||
| @@ -2467,11 +2485,14 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | |||||||
|         lfs_free(file->cache.buffer); |         lfs_free(file->cache.buffer); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     file->flags &= ~LFS_F_OPENED; | ||||||
|     LFS_TRACE("lfs_file_close -> %d", err); |     LFS_TRACE("lfs_file_close -> %d", err); | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |  | ||||||
|     while (true) { |     while (true) { | ||||||
|         // just relocate what exists into new block |         // just relocate what exists into new block | ||||||
|         lfs_block_t nblock; |         lfs_block_t nblock; | ||||||
| @@ -2529,7 +2550,6 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | |||||||
|         lfs_cache_zero(lfs, &lfs->pcache); |         lfs_cache_zero(lfs, &lfs->pcache); | ||||||
|  |  | ||||||
|         file->block = nblock; |         file->block = nblock; | ||||||
|         file->flags &= ~LFS_F_INLINE; |  | ||||||
|         file->flags |= LFS_F_WRITING; |         file->flags |= LFS_F_WRITING; | ||||||
|         return 0; |         return 0; | ||||||
|  |  | ||||||
| @@ -2541,7 +2561,21 @@ relocate: | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { | ||||||
|  |     file->off = file->pos; | ||||||
|  |     lfs_alloc_ack(lfs); | ||||||
|  |     int err = lfs_file_relocate(lfs, file); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     file->flags &= ~LFS_F_INLINE; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |  | ||||||
|     if (file->flags & LFS_F_READING) { |     if (file->flags & LFS_F_READING) { | ||||||
|         if (!(file->flags & LFS_F_INLINE)) { |         if (!(file->flags & LFS_F_INLINE)) { | ||||||
|             lfs_cache_drop(lfs, &file->cache); |             lfs_cache_drop(lfs, &file->cache); | ||||||
| @@ -2557,7 +2591,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | |||||||
|             lfs_file_t orig = { |             lfs_file_t orig = { | ||||||
|                 .ctz.head = file->ctz.head, |                 .ctz.head = file->ctz.head, | ||||||
|                 .ctz.size = file->ctz.size, |                 .ctz.size = file->ctz.size, | ||||||
|                 .flags = LFS_O_RDONLY, |                 .flags = LFS_O_RDONLY | LFS_F_OPENED, | ||||||
|                 .pos = file->pos, |                 .pos = file->pos, | ||||||
|                 .cache = lfs->rcache, |                 .cache = lfs->rcache, | ||||||
|             }; |             }; | ||||||
| @@ -2621,6 +2655,8 @@ relocate: | |||||||
|  |  | ||||||
| int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); |     LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |  | ||||||
|     while (true) { |     while (true) { | ||||||
|         int err = lfs_file_flush(lfs, file); |         int err = lfs_file_flush(lfs, file); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -2674,8 +2710,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | |||||||
|  |  | ||||||
| relocate: | relocate: | ||||||
|         // inline file doesn't fit anymore |         // inline file doesn't fit anymore | ||||||
|         file->off = file->pos; |         err = lfs_file_outline(lfs, file); | ||||||
|         err = lfs_file_relocate(lfs, file); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             file->flags |= LFS_F_ERRED; |             file->flags |= LFS_F_ERRED; | ||||||
|             LFS_TRACE("lfs_file_sync -> %d", err); |             LFS_TRACE("lfs_file_sync -> %d", err); | ||||||
| @@ -2688,14 +2723,12 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | |||||||
|         void *buffer, lfs_size_t size) { |         void *buffer, lfs_size_t size) { | ||||||
|     LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", |     LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", | ||||||
|             (void*)lfs, (void*)file, buffer, size); |             (void*)lfs, (void*)file, buffer, size); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |     LFS_ASSERT((file->flags & 3) != LFS_O_WRONLY); | ||||||
|  |  | ||||||
|     uint8_t *data = buffer; |     uint8_t *data = buffer; | ||||||
|     lfs_size_t nsize = size; |     lfs_size_t nsize = size; | ||||||
|  |  | ||||||
|     if ((file->flags & 3) == LFS_O_WRONLY) { |  | ||||||
|         LFS_TRACE("lfs_file_read -> %"PRId32, LFS_ERR_BADF); |  | ||||||
|         return LFS_ERR_BADF; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (file->flags & LFS_F_WRITING) { |     if (file->flags & LFS_F_WRITING) { | ||||||
|         // flush out any writes |         // flush out any writes | ||||||
|         int err = lfs_file_flush(lfs, file); |         int err = lfs_file_flush(lfs, file); | ||||||
| @@ -2770,14 +2803,12 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | |||||||
|         const void *buffer, lfs_size_t size) { |         const void *buffer, lfs_size_t size) { | ||||||
|     LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", |     LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", | ||||||
|             (void*)lfs, (void*)file, buffer, size); |             (void*)lfs, (void*)file, buffer, size); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |     LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); | ||||||
|  |  | ||||||
|     const uint8_t *data = buffer; |     const uint8_t *data = buffer; | ||||||
|     lfs_size_t nsize = size; |     lfs_size_t nsize = size; | ||||||
|  |  | ||||||
|     if ((file->flags & 3) == LFS_O_RDONLY) { |  | ||||||
|         LFS_TRACE("lfs_file_write -> %"PRId32, LFS_ERR_BADF); |  | ||||||
|         return LFS_ERR_BADF; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (file->flags & LFS_F_READING) { |     if (file->flags & LFS_F_READING) { | ||||||
|         // drop any reads |         // drop any reads | ||||||
|         int err = lfs_file_flush(lfs, file); |         int err = lfs_file_flush(lfs, file); | ||||||
| @@ -2816,9 +2847,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | |||||||
|             lfs_min(0x3fe, lfs_min( |             lfs_min(0x3fe, lfs_min( | ||||||
|                 lfs->cfg->cache_size, lfs->cfg->block_size/8))) { |                 lfs->cfg->cache_size, lfs->cfg->block_size/8))) { | ||||||
|         // inline file doesn't fit anymore |         // inline file doesn't fit anymore | ||||||
|         file->off = file->pos; |         int err = lfs_file_outline(lfs, file); | ||||||
|         lfs_alloc_ack(lfs); |  | ||||||
|         int err = lfs_file_relocate(lfs, file); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             file->flags |= LFS_F_ERRED; |             file->flags |= LFS_F_ERRED; | ||||||
|             LFS_TRACE("lfs_file_write -> %"PRId32, err); |             LFS_TRACE("lfs_file_write -> %"PRId32, err); | ||||||
| @@ -2905,6 +2934,8 @@ 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) { | ||||||
|     LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", |     LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", | ||||||
|             (void*)lfs, (void*)file, off, whence); |             (void*)lfs, (void*)file, off, whence); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|  |  | ||||||
|     // write out everything beforehand, may be noop if rdonly |     // write out everything beforehand, may be noop if rdonly | ||||||
|     int err = lfs_file_flush(lfs, file); |     int err = lfs_file_flush(lfs, file); | ||||||
|     if (err) { |     if (err) { | ||||||
| @@ -2937,10 +2968,8 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | |||||||
| int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { | int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { | ||||||
|     LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", |     LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", | ||||||
|             (void*)lfs, (void*)file, size); |             (void*)lfs, (void*)file, size); | ||||||
|     if ((file->flags & 3) == LFS_O_RDONLY) { |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|         LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_BADF); |     LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); | ||||||
|         return LFS_ERR_BADF; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (size > LFS_FILE_MAX) { |     if (size > LFS_FILE_MAX) { | ||||||
|         LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_INVAL); |         LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_INVAL); | ||||||
| @@ -3003,6 +3032,7 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { | |||||||
|  |  | ||||||
| lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { | lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); |     LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|     (void)lfs; |     (void)lfs; | ||||||
|     LFS_TRACE("lfs_file_tell -> %"PRId32, file->pos); |     LFS_TRACE("lfs_file_tell -> %"PRId32, file->pos); | ||||||
|     return file->pos; |     return file->pos; | ||||||
| @@ -3022,6 +3052,7 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { | |||||||
|  |  | ||||||
| lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { | lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); |     LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); | ||||||
|  |     LFS_ASSERT(file->flags & LFS_F_OPENED); | ||||||
|     (void)lfs; |     (void)lfs; | ||||||
|     if (file->flags & LFS_F_WRITING) { |     if (file->flags & LFS_F_WRITING) { | ||||||
|         LFS_TRACE("lfs_file_size -> %"PRId32, |         LFS_TRACE("lfs_file_size -> %"PRId32, | ||||||
| @@ -3344,8 +3375,14 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) |     LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) | ||||||
|             <= lfs->cfg->block_size); |             <= lfs->cfg->block_size); | ||||||
|  |  | ||||||
|     // we don't support some corner cases |     // block_cycles = 0 is no longer supported. | ||||||
|     LFS_ASSERT(lfs->cfg->block_cycles < 0xffffffff); |     // | ||||||
|  |     // block_cycles is the number of erase cycles before littlefs evicts | ||||||
|  |     // metadata logs as a part of wear leveling. Suggested values are in the | ||||||
|  |     // range of 100-1000, or set block_cycles to -1 to disable block-level | ||||||
|  |     // wear-leveling. | ||||||
|  |     LFS_ASSERT(lfs->cfg->block_cycles != 0); | ||||||
|  |  | ||||||
|  |  | ||||||
|     // setup read cache |     // setup read cache | ||||||
|     if (lfs->cfg->read_buffer) { |     if (lfs->cfg->read_buffer) { | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -136,6 +136,7 @@ enum lfs_open_flags { | |||||||
|     LFS_F_READING = 0x040000, // File has been read since last flush |     LFS_F_READING = 0x040000, // File has been read since last flush | ||||||
|     LFS_F_ERRED   = 0x080000, // An error occured during write |     LFS_F_ERRED   = 0x080000, // An error occured during write | ||||||
|     LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry |     LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry | ||||||
|  |     LFS_F_OPENED  = 0x200000, // File has been opened | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // File seek flags | // File seek flags | ||||||
| @@ -190,9 +191,13 @@ struct lfs_config { | |||||||
|     // Number of erasable blocks on the device. |     // Number of erasable blocks on the device. | ||||||
|     lfs_size_t block_count; |     lfs_size_t block_count; | ||||||
|  |  | ||||||
|     // Number of erase cycles before we should move data to another block. |     // Number of erase cycles before littlefs evicts metadata logs and moves  | ||||||
|     // May be zero, in which case no block-level wear-leveling is performed. |     // the metadata to another block. Suggested values are in the | ||||||
|     uint32_t block_cycles; |     // range 100-1000, with large values having better performance at the cost | ||||||
|  |     // of less consistent wear distribution. | ||||||
|  |     // | ||||||
|  |     // Set to -1 to disable block-level wear-leveling. | ||||||
|  |     int32_t block_cycles; | ||||||
|  |  | ||||||
|     // Size of block caches. Each cache buffers a portion of a block in RAM. |     // Size of block caches. Each cache buffers a portion of a block in RAM. | ||||||
|     // The littlefs needs a read cache, a program cache, and one additional |     // The littlefs needs a read cache, a program cache, and one additional | ||||||
| @@ -204,7 +209,7 @@ struct lfs_config { | |||||||
|     // Size of the lookahead buffer in bytes. A larger lookahead buffer |     // Size of the lookahead buffer in bytes. A larger lookahead buffer | ||||||
|     // increases the number of blocks found during an allocation pass. The |     // increases the number of blocks found during an allocation pass. The | ||||||
|     // lookahead buffer is stored as a compact bitmap, so each byte of RAM |     // lookahead buffer is stored as a compact bitmap, so each byte of RAM | ||||||
|     // can track 8 blocks. Must be a multiple of 4. |     // can track 8 blocks. Must be a multiple of 8. | ||||||
|     lfs_size_t lookahead_size; |     lfs_size_t lookahead_size; | ||||||
|  |  | ||||||
|     // Optional statically allocated read buffer. Must be cache_size. |     // Optional statically allocated read buffer. Must be cache_size. | ||||||
| @@ -216,7 +221,7 @@ struct lfs_config { | |||||||
|     void *prog_buffer; |     void *prog_buffer; | ||||||
|  |  | ||||||
|     // Optional statically allocated lookahead buffer. Must be lookahead_size |     // Optional statically allocated lookahead buffer. Must be lookahead_size | ||||||
|     // and aligned to a 64-bit boundary. By default lfs_malloc is used to |     // and aligned to a 32-bit boundary. By default lfs_malloc is used to | ||||||
|     // allocate this buffer. |     // allocate this buffer. | ||||||
|     void *lookahead_buffer; |     void *lookahead_buffer; | ||||||
|  |  | ||||||
| @@ -528,7 +533,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | |||||||
| // Change the position of the file | // Change the position of the file | ||||||
| // | // | ||||||
| // The change in position is determined by the offset and whence flag. | // The change in position is determined by the offset and whence flag. | ||||||
| // Returns the old position of the file, or a negative error code on failure. | // Returns the new position of the file, or a negative error code on failure. | ||||||
| lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | ||||||
|         lfs_soff_t off, int whence); |         lfs_soff_t off, int whence); | ||||||
|  |  | ||||||
| @@ -545,7 +550,7 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); | |||||||
|  |  | ||||||
| // Change the position of the file to the beginning of the file | // Change the position of the file to the beginning of the file | ||||||
| // | // | ||||||
| // Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) | // Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET) | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); | int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -63,7 +63,7 @@ char path[1024]; | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_CACHE_SIZE | #ifndef LFS_CACHE_SIZE | ||||||
| #define LFS_CACHE_SIZE 64 | #define LFS_CACHE_SIZE (64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_LOOKAHEAD_SIZE | #ifndef LFS_LOOKAHEAD_SIZE | ||||||
|   | |||||||
| @@ -140,20 +140,79 @@ scripts/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Many file test ---" | echo "--- Many files test ---" | ||||||
| scripts/test.py << TEST | scripts/test.py << TEST | ||||||
|     lfs_format(&lfs, &cfg) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
| scripts/test.py << TEST | scripts/test.py << TEST | ||||||
|     // Create 300 files of 6 bytes |     // Create 300 files of 7 bytes | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "directory") => 0; |  | ||||||
|     for (unsigned i = 0; i < 300; i++) { |     for (unsigned i = 0; i < 300; i++) { | ||||||
|         sprintf(path, "file_%03d", i); |         sprintf(path, "file_%03d", i); | ||||||
|         lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; |         lfs_file_open(&lfs, &file, path, | ||||||
|         lfs_size_t size = 6; |                 LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||||
|         memcpy(buffer, "Hello", size); |         lfs_size_t size = 7; | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |         uint8_t wbuffer[1024]; | ||||||
|  |         uint8_t rbuffer[1024]; | ||||||
|  |         snprintf((char*)wbuffer, size, "Hi %03d", i); | ||||||
|  |         lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||||
|  |         lfs_file_rewind(&lfs, &file) => 0; | ||||||
|  |         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||||
|  |         memcmp(wbuffer, rbuffer, size) => 0; | ||||||
|  |         lfs_file_close(&lfs, &file) => 0; | ||||||
|  |     } | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
|  | echo "--- Many files with flush test ---" | ||||||
|  | scripts/test.py << TEST | ||||||
|  |     lfs_format(&lfs, &cfg) => 0; | ||||||
|  | TEST | ||||||
|  | scripts/test.py << TEST | ||||||
|  |     // Create 300 files of 7 bytes | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     for (unsigned i = 0; i < 300; i++) { | ||||||
|  |         sprintf(path, "file_%03d", i); | ||||||
|  |         lfs_file_open(&lfs, &file, path, | ||||||
|  |                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||||
|  |         lfs_size_t size = 7; | ||||||
|  |         uint8_t wbuffer[1024]; | ||||||
|  |         uint8_t rbuffer[1024]; | ||||||
|  |         snprintf((char*)wbuffer, size, "Hi %03d", i); | ||||||
|  |         lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||||
|  |         lfs_file_close(&lfs, &file) => 0; | ||||||
|  |  | ||||||
|  |         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||||
|  |         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||||
|  |         memcmp(wbuffer, rbuffer, size) => 0; | ||||||
|  |         lfs_file_close(&lfs, &file) => 0; | ||||||
|  |     } | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
|  | echo "--- Many files with power cycle test ---" | ||||||
|  | scripts/test.py << TEST | ||||||
|  |     lfs_format(&lfs, &cfg) => 0; | ||||||
|  | TEST | ||||||
|  | scripts/test.py << TEST | ||||||
|  |     // Create 300 files of 7 bytes | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     for (unsigned i = 0; i < 300; i++) { | ||||||
|  |         sprintf(path, "file_%03d", i); | ||||||
|  |         lfs_file_open(&lfs, &file, path, | ||||||
|  |                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; | ||||||
|  |         lfs_size_t size = 7; | ||||||
|  |         uint8_t wbuffer[1024]; | ||||||
|  |         uint8_t rbuffer[1024]; | ||||||
|  |         snprintf((char*)wbuffer, size, "Hi %03d", i); | ||||||
|  |         lfs_file_write(&lfs, &file, wbuffer, size) => size; | ||||||
|  |         lfs_file_close(&lfs, &file) => 0; | ||||||
|  |         lfs_unmount(&lfs) => 0; | ||||||
|  |  | ||||||
|  |         lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||||
|  |         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||||
|  |         memcmp(wbuffer, rbuffer, size) => 0; | ||||||
|         lfs_file_close(&lfs, &file) => 0; |         lfs_file_close(&lfs, &file) => 0; | ||||||
|     } |     } | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user