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 v2-rebase-part2
This commit is contained in:
		
							
								
								
									
										30
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -139,12 +139,15 @@ jobs: | |||||||
|         - LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3) |         - LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3) | ||||||
|         - LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16))) |         - LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16))) | ||||||
|         - LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >>  0))) |         - LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >>  0))) | ||||||
|         # Grab latests patch from repo tags, default to 0 |         # Grab latests patch from repo tags, default to 0, needs finagling to get past github's pagination api | ||||||
|         - LFS_VERSION_PATCH=$(curl -f -u "$GEKY_BOT_RELEASES" |         - PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR. | ||||||
|                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs |         - PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I | ||||||
|                 | jq 'map(.ref | match( |                 | sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' | ||||||
|                     "refs/tags/v'"$LFS_VERSION_MAJOR"'\\.'"$LFS_VERSION_MINOR"'\\.(.*)$") |                 || echo $PREV_URL) | ||||||
|                     .captures[].string | tonumber + 1) | max // 0') |         - LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" | ||||||
|  |                 | jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g") | ||||||
|  |                     .captures[].string | tonumber) | max + 1' | ||||||
|  |                 || echo 0) | ||||||
|         # We have our new version |         # We have our new version | ||||||
|         - LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH" |         - LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH" | ||||||
|         - echo "VERSION $LFS_VERSION" |         - echo "VERSION $LFS_VERSION" | ||||||
| @@ -154,9 +157,19 @@ jobs: | |||||||
|                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \ |                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \ | ||||||
|                 | jq -re '.sha') |                 | jq -re '.sha') | ||||||
|           if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] |           if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] | ||||||
|  |           then | ||||||
|  |             # Create a simple tag | ||||||
|  |             curl -f -u "$GEKY_BOT_RELEASES" -X POST \ | ||||||
|  |                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs \ | ||||||
|  |                 -d "{ | ||||||
|  |                     \"ref\": \"refs/tags/$LFS_VERSION\", | ||||||
|  |                     \"sha\": \"$TRAVIS_COMMIT\" | ||||||
|  |                 }" | ||||||
|  |             # Minor release? | ||||||
|  |             if [[ "$LFS_VERSION" == *.0 ]] | ||||||
|             then |             then | ||||||
|               # Build release notes |               # Build release notes | ||||||
|             PREV=$(git tag --sort=-v:refname -l "v*" | head -1) |               PREV=$(git tag --sort=-v:refname -l "v*.0" | head -1) | ||||||
|               if [ ! -z "$PREV" ] |               if [ ! -z "$PREV" ] | ||||||
|               then |               then | ||||||
|                   echo "PREV $PREV" |                   echo "PREV $PREV" | ||||||
| @@ -169,11 +182,12 @@ jobs: | |||||||
|                   https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \ |                   https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \ | ||||||
|                   -d "{ |                   -d "{ | ||||||
|                       \"tag_name\": \"$LFS_VERSION\", |                       \"tag_name\": \"$LFS_VERSION\", | ||||||
|                     \"target_commitish\": \"$TRAVIS_COMMIT\", |  | ||||||
|                       \"name\": \"${LFS_VERSION%.0}\", |                       \"name\": \"${LFS_VERSION%.0}\", | ||||||
|  |                       \"draft\": true, | ||||||
|                       \"body\": $(jq -sR '.' <<< "$CHANGES") |                       \"body\": $(jq -sR '.' <<< "$CHANGES") | ||||||
|                   }" |                   }" | ||||||
|             fi |             fi | ||||||
|  |           fi | ||||||
|  |  | ||||||
| # Manage statuses | # Manage statuses | ||||||
| before_install: | before_install: | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							| @@ -25,7 +25,8 @@ ifdef WORD | |||||||
| override CFLAGS += -m$(WORD) | override CFLAGS += -m$(WORD) | ||||||
| endif | endif | ||||||
| override CFLAGS += -I. | override CFLAGS += -I. | ||||||
| override CFLAGS += -std=c99 -Wall -pedantic -Wshadow -Wunused-parameter | override CFLAGS += -std=c99 -Wall -pedantic | ||||||
|  | override CFLAGS += -Wshadow -Wunused-parameter -Wjump-misses-init -Wsign-compare | ||||||
|  |  | ||||||
|  |  | ||||||
| all: $(TARGET) | all: $(TARGET) | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							| @@ -176,3 +176,18 @@ handy. | |||||||
| [littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for | [littlefs-js](https://github.com/geky/littlefs-js) - A javascript wrapper for | ||||||
| littlefs. I'm not sure why you would want this, but it is handy for demos. | littlefs. I'm not sure why you would want this, but it is handy for demos. | ||||||
| You can see it in action [here](http://littlefs.geky.net/demo.html). | You can see it in action [here](http://littlefs.geky.net/demo.html). | ||||||
|  |  | ||||||
|  | [mklfs](https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src) - | ||||||
|  | A command line tool built by the [Lua RTOS](https://github.com/whitecatboard/Lua-RTOS-ESP32) | ||||||
|  | guys for making littlefs images from a host PC. Supports Windows, Mac OS, | ||||||
|  | and Linux. | ||||||
|  |  | ||||||
|  | [SPIFFS](https://github.com/pellepl/spiffs) - Another excellent embedded | ||||||
|  | filesystem for NOR flash. As a more traditional logging filesystem with full | ||||||
|  | static wear-leveling, SPIFFS will likely outperform littlefs on small | ||||||
|  | memories such as the internal flash on microcontrollers. | ||||||
|  |  | ||||||
|  | [Dhara](https://github.com/dlbeer/dhara) - An interesting NAND flash | ||||||
|  | translation layer designed for small MCUs. It offers static wear-leveling and | ||||||
|  | power-resilience with only a fixed O(|address|) pointer structure stored on | ||||||
|  | each block and in RAM. | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ static inline void lfs_emubd_tole32(lfs_emubd_t *emu) { | |||||||
|     emu->stats.prog_count  = lfs_tole32(emu->stats.prog_count); |     emu->stats.prog_count  = lfs_tole32(emu->stats.prog_count); | ||||||
|     emu->stats.erase_count = lfs_tole32(emu->stats.erase_count); |     emu->stats.erase_count = lfs_tole32(emu->stats.erase_count); | ||||||
|  |  | ||||||
|     for (int i = 0; i < sizeof(emu->history.blocks) / |     for (unsigned i = 0; i < sizeof(emu->history.blocks) / | ||||||
|             sizeof(emu->history.blocks[0]); i++) { |             sizeof(emu->history.blocks[0]); i++) { | ||||||
|         emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]); |         emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]); | ||||||
|     } |     } | ||||||
| @@ -46,7 +46,7 @@ static inline void lfs_emubd_fromle32(lfs_emubd_t *emu) { | |||||||
|     emu->stats.prog_count  = lfs_fromle32(emu->stats.prog_count); |     emu->stats.prog_count  = lfs_fromle32(emu->stats.prog_count); | ||||||
|     emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count); |     emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count); | ||||||
|  |  | ||||||
|     for (int i = 0; i < sizeof(emu->history.blocks) / |     for (unsigned i = 0; i < sizeof(emu->history.blocks) / | ||||||
|             sizeof(emu->history.blocks[0]); i++) { |             sizeof(emu->history.blocks[0]); i++) { | ||||||
|         emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]); |         emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]); | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -322,14 +322,14 @@ static inline void lfs_global_xor(struct lfs_globals *a, | |||||||
|         const struct lfs_globals *b) { |         const struct lfs_globals *b) { | ||||||
|     uint32_t *a32 = (uint32_t *)a; |     uint32_t *a32 = (uint32_t *)a; | ||||||
|     const uint32_t *b32 = (const uint32_t *)b; |     const uint32_t *b32 = (const uint32_t *)b; | ||||||
|     for (int i = 0; i < sizeof(struct lfs_globals)/4; i++) { |     for (unsigned i = 0; i < sizeof(struct lfs_globals)/4; i++) { | ||||||
|         a32[i] ^= b32[i]; |         a32[i] ^= b32[i]; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline bool lfs_global_iszero(const struct lfs_globals *a) { | static inline bool lfs_global_iszero(const struct lfs_globals *a) { | ||||||
|     const uint32_t *a32 = (const uint32_t *)a; |     const uint32_t *a32 = (const uint32_t *)a; | ||||||
|     for (int i = 0; i < sizeof(struct lfs_globals)/4; i++) { |     for (unsigned i = 0; i < sizeof(struct lfs_globals)/4; i++) { | ||||||
|         if (a32[i] != 0) { |         if (a32[i] != 0) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| @@ -387,6 +387,7 @@ static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { | |||||||
|     superblock->name_max    = lfs_fromle32(superblock->name_max); |     superblock->name_max    = lfs_fromle32(superblock->name_max); | ||||||
|     superblock->inline_max  = lfs_fromle32(superblock->inline_max); |     superblock->inline_max  = lfs_fromle32(superblock->inline_max); | ||||||
|     superblock->attr_max    = lfs_fromle32(superblock->attr_max); |     superblock->attr_max    = lfs_fromle32(superblock->attr_max); | ||||||
|  |     superblock->file_max    = lfs_fromle32(superblock->file_max); | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { | static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { | ||||||
| @@ -396,6 +397,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { | |||||||
|     superblock->name_max    = lfs_tole32(superblock->name_max); |     superblock->name_max    = lfs_tole32(superblock->name_max); | ||||||
|     superblock->inline_max  = lfs_tole32(superblock->inline_max); |     superblock->inline_max  = lfs_tole32(superblock->inline_max); | ||||||
|     superblock->attr_max    = lfs_tole32(superblock->attr_max); |     superblock->attr_max    = lfs_tole32(superblock->attr_max); | ||||||
|  |     superblock->file_max    = lfs_tole32(superblock->file_max); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1347,13 +1349,13 @@ commit: | |||||||
|                         (const lfs_block_t[2]){0, 1}) == 0) { |                         (const lfs_block_t[2]){0, 1}) == 0) { | ||||||
|                     // we're writing too much to the superblock, |                     // we're writing too much to the superblock, | ||||||
|                     // should we expand? |                     // should we expand? | ||||||
|                     lfs_stag_t res = lfs_fs_size(lfs); |                     lfs_ssize_t res = lfs_fs_size(lfs); | ||||||
|                     if (res < 0) { |                     if (res < 0) { | ||||||
|                         return res; |                         return res; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     // do we have enough space to expand? |                     // do we have enough space to expand? | ||||||
|                     if (res < lfs->cfg->block_count/2) { |                     if ((lfs_size_t)res < lfs->cfg->block_count/2) { | ||||||
|                         LFS_DEBUG("Expanding superblock at rev %"PRIu32, |                         LFS_DEBUG("Expanding superblock at rev %"PRIu32, | ||||||
|                                 dir->rev); |                                 dir->rev); | ||||||
|                         exhausted = true; |                         exhausted = true; | ||||||
| @@ -1376,6 +1378,7 @@ commit: | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (true) { | ||||||
|             // write out header |             // write out header | ||||||
|             uint32_t rev = lfs_tole32(dir->rev); |             uint32_t rev = lfs_tole32(dir->rev); | ||||||
|             err = lfs_commit_prog(lfs, &commit, &rev, sizeof(rev)); |             err = lfs_commit_prog(lfs, &commit, &rev, sizeof(rev)); | ||||||
| @@ -1463,6 +1466,7 @@ commit: | |||||||
|             dir->off = commit.off; |             dir->off = commit.off; | ||||||
|             dir->etag = commit.ptag; |             dir->etag = commit.ptag; | ||||||
|             dir->erased = true; |             dir->erased = true; | ||||||
|  |         } | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
| split: | split: | ||||||
| @@ -1560,7 +1564,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
|         // Wait, we have the move? Just cancel this out here |         // Wait, we have the move? Just cancel this out here | ||||||
|         // We need to, or else the move can become outdated |         // We need to, or else the move can become outdated | ||||||
|         cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.id, 0); |         cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.id, 0); | ||||||
|         cancelattr.next = attrs; |         cancelattr.next = attrs; // TODO need order | ||||||
|         attrs = &cancelattr; |         attrs = &cancelattr; | ||||||
|  |  | ||||||
|         cancels.hasmove = lfs->globals.hasmove; |         cancels.hasmove = lfs->globals.hasmove; | ||||||
| @@ -1602,11 +1606,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
|         attrcount += 1; |         attrcount += 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     while (true) { |     if (dir->erased) { | ||||||
|         if (!dir->erased) { |  | ||||||
|             goto compact; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // try to commit |         // try to commit | ||||||
|         struct lfs_commit commit = { |         struct lfs_commit commit = { | ||||||
|             .block = dir->pair[0], |             .block = dir->pair[0], | ||||||
| @@ -1668,18 +1668,15 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
|         dir->etag = commit.ptag; |         dir->etag = commit.ptag; | ||||||
|         // successful commit, update globals |         // successful commit, update globals | ||||||
|         lfs_global_zero(&lfs->locals); |         lfs_global_zero(&lfs->locals); | ||||||
|         break; |     } else { | ||||||
|  |  | ||||||
| compact: | compact: | ||||||
|         // fall back to compaction |         // fall back to compaction | ||||||
|         lfs_cache_drop(lfs, &lfs->pcache); |         lfs_cache_drop(lfs, &lfs->pcache); | ||||||
|  |  | ||||||
|         err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count); |         int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         break; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // update globals that are affected |     // update globals that are affected | ||||||
| @@ -2021,6 +2018,7 @@ static int lfs_ctz_extend(lfs_t *lfs, | |||||||
|         } |         } | ||||||
|         LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count); |         LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count); | ||||||
|  |  | ||||||
|  |         if (true) { | ||||||
|             err = lfs_bd_erase(lfs, nblock); |             err = lfs_bd_erase(lfs, nblock); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 if (err == LFS_ERR_CORRUPT) { |                 if (err == LFS_ERR_CORRUPT) { | ||||||
| @@ -2098,6 +2096,7 @@ static int lfs_ctz_extend(lfs_t *lfs, | |||||||
|             *block = nblock; |             *block = nblock; | ||||||
|             *off = 4*skips; |             *off = 4*skips; | ||||||
|             return 0; |             return 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
| relocate: | relocate: | ||||||
|         LFS_DEBUG("Bad block at %"PRIu32, nblock); |         LFS_DEBUG("Bad block at %"PRIu32, nblock); | ||||||
| @@ -2596,6 +2595,11 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | |||||||
|         file->pos = file->ctz.size; |         file->pos = file->ctz.size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (file->pos + size > lfs->file_max) { | ||||||
|  |         // Larger than file limit? | ||||||
|  |         return LFS_ERR_FBIG; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) { |     if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) { | ||||||
|         // fill with zeros |         // fill with zeros | ||||||
|         lfs_off_t pos = file->pos; |         lfs_off_t pos = file->pos; | ||||||
| @@ -2704,24 +2708,24 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | |||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // update pos |     // find new pos | ||||||
|  |     lfs_off_t npos = file->pos; | ||||||
|     if (whence == LFS_SEEK_SET) { |     if (whence == LFS_SEEK_SET) { | ||||||
|         file->pos = off; |         npos = off; | ||||||
|     } else if (whence == LFS_SEEK_CUR) { |     } else if (whence == LFS_SEEK_CUR) { | ||||||
|         if (off < 0 && (lfs_off_t)-off > file->pos) { |         npos = file->pos + off; | ||||||
|             return LFS_ERR_INVAL; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         file->pos = file->pos + off; |  | ||||||
|     } else if (whence == LFS_SEEK_END) { |     } else if (whence == LFS_SEEK_END) { | ||||||
|         if (off < 0 && (lfs_off_t)-off > file->ctz.size) { |         npos = file->ctz.size + off; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (npos < 0 || npos > lfs->file_max) { | ||||||
|  |         // file position out of range | ||||||
|         return LFS_ERR_INVAL; |         return LFS_ERR_INVAL; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         file->pos = file->ctz.size + off; |     // update pos | ||||||
|     } |     file->pos = npos; | ||||||
|  |     return npos; | ||||||
|     return file->pos; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| 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) { | ||||||
| @@ -3112,6 +3116,12 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         lfs->attr_max = LFS_ATTR_MAX; |         lfs->attr_max = LFS_ATTR_MAX; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX); | ||||||
|  |     lfs->file_max = lfs->cfg->file_max; | ||||||
|  |     if (!lfs->file_max) { | ||||||
|  |         lfs->file_max = LFS_FILE_MAX; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // setup default state |     // setup default state | ||||||
|     lfs->root[0] = 0xffffffff; |     lfs->root[0] = 0xffffffff; | ||||||
|     lfs->root[1] = 0xffffffff; |     lfs->root[1] = 0xffffffff; | ||||||
| @@ -3145,7 +3155,9 @@ static int lfs_deinit(lfs_t *lfs) { | |||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||||
|     int err = lfs_init(lfs, cfg); |     int err = 0; | ||||||
|  |     if (true) { | ||||||
|  |         err = lfs_init(lfs, cfg); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
| @@ -3173,6 +3185,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|             .name_max    = lfs->name_max, |             .name_max    = lfs->name_max, | ||||||
|             .inline_max  = lfs->inline_max, |             .inline_max  = lfs->inline_max, | ||||||
|             .attr_max    = lfs->attr_max, |             .attr_max    = lfs->attr_max, | ||||||
|  |             .file_max    = lfs->file_max, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         lfs_superblock_tole32(&superblock); |         lfs_superblock_tole32(&superblock); | ||||||
| @@ -3190,6 +3203,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         if (err) { |         if (err) { | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
| cleanup: | cleanup: | ||||||
|     lfs_deinit(lfs); |     lfs_deinit(lfs); | ||||||
| @@ -3276,6 +3290,17 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|                 lfs->attr_max = superblock.attr_max; |                 lfs->attr_max = superblock.attr_max; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             if (superblock.file_max) { | ||||||
|  |                 if (superblock.file_max > lfs->file_max) { | ||||||
|  |                     LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")", | ||||||
|  |                             superblock.file_max, lfs->file_max); | ||||||
|  |                     err = LFS_ERR_INVAL; | ||||||
|  |                     goto cleanup; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 lfs->file_max = superblock.file_max; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // has globals? |         // has globals? | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -66,6 +66,15 @@ typedef uint32_t lfs_block_t; | |||||||
| #define LFS_ATTR_MAX 0x1ffe | #define LFS_ATTR_MAX 0x1ffe | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | // Maximum size of a file in bytes, may be redefined to limit to support other | ||||||
|  | // drivers. Limited on disk to <= 4294967296. However, above 2147483647 the | ||||||
|  | // functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return | ||||||
|  | // incorrect values due to signed sizes. Stored in superblock and must be | ||||||
|  | // respected by other littlefs drivers. | ||||||
|  | #ifndef LFS_FILE_MAX | ||||||
|  | #define LFS_FILE_MAX 2147483647 | ||||||
|  | #endif | ||||||
|  |  | ||||||
| // Possible error codes, these are negative to allow | // Possible error codes, these are negative to allow | ||||||
| // valid positive return values | // valid positive return values | ||||||
| enum lfs_error { | enum lfs_error { | ||||||
| @@ -78,6 +87,7 @@ enum lfs_error { | |||||||
|     LFS_ERR_ISDIR       = -21,  // Entry is a dir |     LFS_ERR_ISDIR       = -21,  // Entry is a dir | ||||||
|     LFS_ERR_NOTEMPTY    = -39,  // Dir is not empty |     LFS_ERR_NOTEMPTY    = -39,  // Dir is not empty | ||||||
|     LFS_ERR_BADF        = -9,   // Bad file number |     LFS_ERR_BADF        = -9,   // Bad file number | ||||||
|  |     LFS_ERR_FBIG        = -27,  // File too large | ||||||
|     LFS_ERR_INVAL       = -22,  // Invalid parameter |     LFS_ERR_INVAL       = -22,  // Invalid parameter | ||||||
|     LFS_ERR_NOSPC       = -28,  // No space left on device |     LFS_ERR_NOSPC       = -28,  // No space left on device | ||||||
|     LFS_ERR_NOMEM       = -12,  // No more memory available |     LFS_ERR_NOMEM       = -12,  // No more memory available | ||||||
| @@ -233,6 +243,11 @@ struct lfs_config { | |||||||
|     // LFS_ATTR_MAX when zero. Stored in superblock and must be respected by |     // LFS_ATTR_MAX when zero. Stored in superblock and must be respected by | ||||||
|     // other littlefs drivers. |     // other littlefs drivers. | ||||||
|     lfs_size_t attr_max; |     lfs_size_t attr_max; | ||||||
|  |  | ||||||
|  |     // Optional upper limit on files in bytes. No downside for larger files | ||||||
|  |     // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored | ||||||
|  |     // in superblock and must be respected by other littlefs drivers. | ||||||
|  |     lfs_size_t file_max; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // File info structure | // File info structure | ||||||
| @@ -346,6 +361,7 @@ typedef struct lfs_superblock { | |||||||
|     lfs_size_t name_max; |     lfs_size_t name_max; | ||||||
|     lfs_size_t inline_max; |     lfs_size_t inline_max; | ||||||
|     lfs_size_t attr_max; |     lfs_size_t attr_max; | ||||||
|  |     lfs_size_t file_max; | ||||||
| } lfs_superblock_t; | } lfs_superblock_t; | ||||||
|  |  | ||||||
| // The littlefs filesystem type | // The littlefs filesystem type | ||||||
| @@ -378,11 +394,10 @@ typedef struct lfs { | |||||||
|     } free; |     } free; | ||||||
|  |  | ||||||
|     const struct lfs_config *cfg; |     const struct lfs_config *cfg; | ||||||
|     lfs_size_t block_size; |  | ||||||
|     lfs_size_t block_count; |  | ||||||
|     lfs_size_t name_max; |     lfs_size_t name_max; | ||||||
|     lfs_size_t inline_max; |     lfs_size_t inline_max; | ||||||
|     lfs_size_t attr_max; |     lfs_size_t attr_max; | ||||||
|  |     lfs_size_t file_max; | ||||||
| } lfs_t; | } lfs_t; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -32,18 +32,18 @@ lfs_alloc_singleproc() { | |||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     const char *names[] = {"bacon", "eggs", "pancakes"}; |     const char *names[] = {"bacon", "eggs", "pancakes"}; | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { |     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||||
|         sprintf((char*)buffer, "$1/%s", names[n]); |         sprintf((char*)buffer, "$1/%s", names[n]); | ||||||
|         lfs_file_open(&lfs, &file[n], (char*)buffer, |         lfs_file_open(&lfs, &file[n], (char*)buffer, | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||||
|     } |     } | ||||||
|     for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { |     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||||
|         size = strlen(names[n]); |         size = strlen(names[n]); | ||||||
|         for (int i = 0; i < $SIZE; i++) { |         for (int i = 0; i < $SIZE; i++) { | ||||||
|             lfs_file_write(&lfs, &file[n], names[n], size) => size; |             lfs_file_write(&lfs, &file[n], names[n], size) => size; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { |     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||||
|         lfs_file_close(&lfs, &file[n]) => 0; |         lfs_file_close(&lfs, &file[n]) => 0; | ||||||
|     } |     } | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|   | |||||||
| @@ -326,13 +326,42 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
|  | echo "--- Multi-block rename ---" | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|  |         sprintf((char*)buffer, "cactus/test%03d", i); | ||||||
|  |         sprintf((char*)wbuffer, "cactus/tedd%03d", i); | ||||||
|  |         lfs_rename(&lfs, (char*)buffer, (char*)wbuffer) => 0; | ||||||
|  |     } | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     lfs_dir_open(&lfs, &dir[0], "cactus") => 0; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, ".") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "..") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|  |         sprintf((char*)buffer, "tedd%03d", i); | ||||||
|  |         lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |         strcmp(info.name, (char*)buffer) => 0; | ||||||
|  |         info.type => LFS_TYPE_DIR; | ||||||
|  |     } | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
| echo "--- Multi-block remove ---" | echo "--- Multi-block remove ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY; |     lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY; | ||||||
|  |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|         sprintf((char*)buffer, "cactus/test%03d", i); |         sprintf((char*)buffer, "cactus/tedd%03d", i); | ||||||
|         lfs_remove(&lfs, (char*)buffer) => 0; |         lfs_remove(&lfs, (char*)buffer) => 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -391,13 +420,43 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
|  | echo "--- Multi-block rename with files ---" | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|  |         sprintf((char*)buffer, "prickly-pear/test%03d", i); | ||||||
|  |         sprintf((char*)wbuffer, "prickly-pear/tedd%03d", i); | ||||||
|  |         lfs_rename(&lfs, (char*)buffer, (char*)wbuffer) => 0; | ||||||
|  |     } | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |     lfs_dir_open(&lfs, &dir[0], "prickly-pear") => 0; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, ".") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "..") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|  |         sprintf((char*)buffer, "tedd%03d", i); | ||||||
|  |         lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |         strcmp(info.name, (char*)buffer) => 0; | ||||||
|  |         info.type => LFS_TYPE_REG; | ||||||
|  |         info.size => 6; | ||||||
|  |     } | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
| echo "--- Multi-block remove with files ---" | echo "--- Multi-block remove with files ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; |     lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; | ||||||
|  |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|         sprintf((char*)buffer, "prickly-pear/test%03d", i); |         sprintf((char*)buffer, "prickly-pear/tedd%03d", i); | ||||||
|         lfs_remove(&lfs, (char*)buffer) => 0; |         lfs_remove(&lfs, (char*)buffer) => 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -301,7 +301,7 @@ tests/test.py << TEST | |||||||
|     size = strlen("hedgehoghog"); |     size = strlen("hedgehoghog"); | ||||||
|     const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; |     const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; | ||||||
|  |  | ||||||
|     for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { |     for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { | ||||||
|         lfs_soff_t off = offsets[i]; |         lfs_soff_t off = offsets[i]; | ||||||
|         memcpy(buffer, "hedgehoghog", size); |         memcpy(buffer, "hedgehoghog", size); | ||||||
|         lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; |         lfs_file_seek(&lfs, &file[0], off, LFS_SEEK_SET) => off; | ||||||
|   | |||||||
| @@ -23,14 +23,14 @@ tests/test.py << TEST | |||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |  | ||||||
|     for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { |     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { | ||||||
|         sprintf((char*)buffer, "hairyhead%d", i); |         sprintf((char*)buffer, "hairyhead%d", i); | ||||||
|         lfs_file_open(&lfs, &file[0], (const char*)buffer, |         lfs_file_open(&lfs, &file[0], (const char*)buffer, | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||||
|  |  | ||||||
|         strcpy((char*)buffer, "hair"); |         strcpy((char*)buffer, "hair"); | ||||||
|         size = strlen((char*)buffer); |         size = strlen((char*)buffer); | ||||||
|         for (int j = 0; j < startsizes[i]; j += size) { |         for (lfs_off_t j = 0; j < startsizes[i]; j += size) { | ||||||
|             lfs_file_write(&lfs, &file[0], buffer, size) => size; |             lfs_file_write(&lfs, &file[0], buffer, size) => size; | ||||||
|         } |         } | ||||||
|         lfs_file_size(&lfs, &file[0]) => startsizes[i]; |         lfs_file_size(&lfs, &file[0]) => startsizes[i]; | ||||||
| @@ -55,13 +55,13 @@ tests/test.py << TEST | |||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |  | ||||||
|     for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { |     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { | ||||||
|         sprintf((char*)buffer, "hairyhead%d", i); |         sprintf((char*)buffer, "hairyhead%d", i); | ||||||
|         lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0; |         lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDWR) => 0; | ||||||
|         lfs_file_size(&lfs, &file[0]) => hotsizes[i]; |         lfs_file_size(&lfs, &file[0]) => hotsizes[i]; | ||||||
|  |  | ||||||
|         size = strlen("hair"); |         size = strlen("hair"); | ||||||
|         int j = 0; |         lfs_off_t j = 0; | ||||||
|         for (; j < startsizes[i] && j < hotsizes[i]; j += size) { |         for (; j < startsizes[i] && j < hotsizes[i]; j += size) { | ||||||
|             lfs_file_read(&lfs, &file[0], buffer, size) => size; |             lfs_file_read(&lfs, &file[0], buffer, size) => size; | ||||||
|             memcmp(buffer, "hair", size) => 0; |             memcmp(buffer, "hair", size) => 0; | ||||||
| @@ -87,13 +87,13 @@ tests/test.py << TEST | |||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|  |  | ||||||
|     for (int i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { |     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { | ||||||
|         sprintf((char*)buffer, "hairyhead%d", i); |         sprintf((char*)buffer, "hairyhead%d", i); | ||||||
|         lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0; |         lfs_file_open(&lfs, &file[0], (const char*)buffer, LFS_O_RDONLY) => 0; | ||||||
|         lfs_file_size(&lfs, &file[0]) => coldsizes[i]; |         lfs_file_size(&lfs, &file[0]) => coldsizes[i]; | ||||||
|  |  | ||||||
|         size = strlen("hair"); |         size = strlen("hair"); | ||||||
|         int j = 0; |         lfs_off_t j = 0; | ||||||
|         for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; |         for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; | ||||||
|                 j += size) { |                 j += size) { | ||||||
|             lfs_file_read(&lfs, &file[0], buffer, size) => size; |             lfs_file_read(&lfs, &file[0], buffer, size) => size; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user