mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 00:32:38 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into v2-alpha
This commit is contained in:
		
							
								
								
									
										69
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ script: | ||||
|   # compile and find the code size with the smallest configuration | ||||
|   - make clean size | ||||
|         OBJ="$(ls lfs*.o | tr '\n' ' ')" | ||||
|         CFLAGS+="-DLFS_NO{ASSERT,DEBUG,WARN,ERROR}" | ||||
|         CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR" | ||||
|         | tee sizes | ||||
|  | ||||
|   # update status if we succeeded, compare with master if possible | ||||
| @@ -135,53 +135,44 @@ jobs: | ||||
|         - STAGE=deploy | ||||
|         - NAME=deploy | ||||
|       script: | ||||
|         # Update tag for version defined in lfs.h | ||||
|         # Find version defined in lfs.h | ||||
|         - LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3) | ||||
|         - LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16))) | ||||
|         - LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >>  0))) | ||||
|         - LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR" | ||||
|         - echo "littlefs version $LFS_VERSION" | ||||
|         # Grab latests patch from repo tags, default to 0 | ||||
|         - LFS_VERSION_PATCH=$(curl -f -u "$GEKY_BOT_RELEASES" | ||||
|                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs | ||||
|                 | jq 'map(.ref | match( | ||||
|                     "refs/tags/v'"$LFS_VERSION_MAJOR"'\\.'"$LFS_VERSION_MINOR"'\\.(.*)$") | ||||
|                     .captures[].string | tonumber + 1) | max // 0') | ||||
|         # We have our new version | ||||
|         - LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH" | ||||
|         - echo "VERSION $LFS_VERSION" | ||||
|         - | | ||||
|           curl -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\" | ||||
|             }" | ||||
|         - | | ||||
|           curl -f -u $GEKY_BOT_RELEASES -X PATCH \ | ||||
|             https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/$LFS_VERSION \ | ||||
|             -d "{ | ||||
|               \"sha\": \"$TRAVIS_COMMIT\" | ||||
|             }" | ||||
|         # Create release notes from commits | ||||
|         - LFS_PREV_VERSION="v$LFS_VERSION_MAJOR.$(($LFS_VERSION_MINOR-1))" | ||||
|         - | | ||||
|           if [ $(git tag -l "$LFS_PREV_VERSION") ] | ||||
|           # Check that we're the most recent commit | ||||
|           CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \ | ||||
|                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \ | ||||
|                 | jq -re '.sha') | ||||
|           if [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] | ||||
|           then | ||||
|             curl -u $GEKY_BOT_RELEASES -X POST \ | ||||
|             # Build release notes | ||||
|             PREV=$(git tag --sort=-v:refname -l "v*" | head -1) | ||||
|             if [ ! -z "$PREV" ] | ||||
|             then | ||||
|                 echo "PREV $PREV" | ||||
|                 CHANGES=$'### Changes\n\n'$( \ | ||||
|                     git log --oneline $PREV.. --grep='^Merge' --invert-grep) | ||||
|                 printf "CHANGES\n%s\n\n" "$CHANGES" | ||||
|             fi | ||||
|             # Create the release | ||||
|             curl -f -u "$GEKY_BOT_RELEASES" -X POST \ | ||||
|                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \ | ||||
|                 -d "{ | ||||
|                     \"tag_name\": \"$LFS_VERSION\", | ||||
|                     \"name\": \"$LFS_VERSION\" | ||||
|                     \"target_commitish\": \"$TRAVIS_COMMIT\", | ||||
|                     \"name\": \"${LFS_VERSION%.0}\", | ||||
|                     \"body\": $(jq -sR '.' <<< "$CHANGES") | ||||
|                 }" | ||||
|             RELEASE=$( | ||||
|                 curl -f -u $GEKY_BOT_RELEASES \ | ||||
|                     https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases/tags/$LFS_VERSION | ||||
|             ) | ||||
|             CHANGES=$( | ||||
|                 git log --oneline $LFS_PREV_VERSION.. --grep='^Merge' --invert-grep | ||||
|             ) | ||||
|             curl -f -u $GEKY_BOT_RELEASES -X PATCH \ | ||||
|                 https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases/$( | ||||
|                     jq -r '.id' <<< "$RELEASE" | ||||
|                 ) \ | ||||
|                 -d "$( | ||||
|                     jq -s '{ | ||||
|                         "body": ((.[0] // "" | sub("(?<=\n)#+ Changes.*"; ""; "mi")) | ||||
|                             + "### Changes\n\n" + .[1]) | ||||
|                     }' <(jq '.body' <<< "$RELEASE") <(jq -sR '.' <<< "$CHANGES") | ||||
|                 )" | ||||
|           fi | ||||
|  | ||||
| # Manage statuses | ||||
|   | ||||
							
								
								
									
										183
									
								
								LICENSE.md
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								LICENSE.md
									
									
									
									
									
								
							| @@ -1,165 +1,24 @@ | ||||
| Apache License | ||||
| Version 2.0, January 2004 | ||||
| http://www.apache.org/licenses/ | ||||
| Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  | ||||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
| Redistribution and use in source and binary forms, with or without modification, | ||||
| are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Definitions. | ||||
| -  Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
| -  Redistributions in binary form must reproduce the above copyright notice, this | ||||
|    list of conditions and the following disclaimer in the documentation and/or | ||||
|    other materials provided with the distribution. | ||||
| -  Neither the name of ARM nor the names of its contributors may be used to | ||||
|    endorse or promote products derived from this software without specific prior | ||||
|    written permission. | ||||
|  | ||||
| "License" shall mean the terms and conditions for use, reproduction, and | ||||
| distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
| "Licensor" shall mean the copyright owner or entity authorized by the copyright | ||||
| owner that is granting the License. | ||||
|  | ||||
| "Legal Entity" shall mean the union of the acting entity and all other entities | ||||
| that control, are controlled by, or are under common control with that entity. | ||||
| For the purposes of this definition, "control" means (i) the power, direct or | ||||
| indirect, to cause the direction or management of such entity, whether by | ||||
| contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
| "You" (or "Your") shall mean an individual or Legal Entity exercising | ||||
| permissions granted by this License. | ||||
|  | ||||
| "Source" form shall mean the preferred form for making modifications, including | ||||
| but not limited to software source code, documentation source, and configuration | ||||
| files. | ||||
|  | ||||
| "Object" form shall mean any form resulting from mechanical transformation or | ||||
| translation of a Source form, including but not limited to compiled object code, | ||||
| generated documentation, and conversions to other media types. | ||||
|  | ||||
| "Work" shall mean the work of authorship, whether in Source or Object form, made | ||||
| available under the License, as indicated by a copyright notice that is included | ||||
| in or attached to the work (an example is provided in the Appendix below). | ||||
|  | ||||
| "Derivative Works" shall mean any work, whether in Source or Object form, that | ||||
| is based on (or derived from) the Work and for which the editorial revisions, | ||||
| annotations, elaborations, or other modifications represent, as a whole, an | ||||
| original work of authorship. For the purposes of this License, Derivative Works | ||||
| shall not include works that remain separable from, or merely link (or bind by | ||||
| name) to the interfaces of, the Work and Derivative Works thereof. | ||||
|  | ||||
| "Contribution" shall mean any work of authorship, including the original version | ||||
| of the Work and any modifications or additions to that Work or Derivative Works | ||||
| thereof, that is intentionally submitted to Licensor for inclusion in the Work | ||||
| by the copyright owner or by an individual or Legal Entity authorized to submit | ||||
| on behalf of the copyright owner. For the purposes of this definition, | ||||
| "submitted" means any form of electronic, verbal, or written communication sent | ||||
| to the Licensor or its representatives, including but not limited to | ||||
| communication on electronic mailing lists, source code control systems, and | ||||
| issue tracking systems that are managed by, or on behalf of, the Licensor for | ||||
| the purpose of discussing and improving the Work, but excluding communication | ||||
| that is conspicuously marked or otherwise designated in writing by the copyright | ||||
| owner as "Not a Contribution." | ||||
|  | ||||
| "Contributor" shall mean Licensor and any individual or Legal Entity on behalf | ||||
| of whom a Contribution has been received by Licensor and subsequently | ||||
| incorporated within the Work. | ||||
|  | ||||
| 2. Grant of Copyright License. | ||||
|  | ||||
| Subject to the terms and conditions of this License, each Contributor hereby | ||||
| grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, | ||||
| irrevocable copyright license to reproduce, prepare Derivative Works of, | ||||
| publicly display, publicly perform, sublicense, and distribute the Work and such | ||||
| Derivative Works in Source or Object form. | ||||
|  | ||||
| 3. Grant of Patent License. | ||||
|  | ||||
| Subject to the terms and conditions of this License, each Contributor hereby | ||||
| grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, | ||||
| irrevocable (except as stated in this section) patent license to make, have | ||||
| made, use, offer to sell, sell, import, and otherwise transfer the Work, where | ||||
| such license applies only to those patent claims licensable by such Contributor | ||||
| that are necessarily infringed by their Contribution(s) alone or by combination | ||||
| of their Contribution(s) with the Work to which such Contribution(s) was | ||||
| submitted. If You institute patent litigation against any entity (including a | ||||
| cross-claim or counterclaim in a lawsuit) alleging that the Work or a | ||||
| Contribution incorporated within the Work constitutes direct or contributory | ||||
| patent infringement, then any patent licenses granted to You under this License | ||||
| for that Work shall terminate as of the date such litigation is filed. | ||||
|  | ||||
| 4. Redistribution. | ||||
|  | ||||
| You may reproduce and distribute copies of the Work or Derivative Works thereof | ||||
| in any medium, with or without modifications, and in Source or Object form, | ||||
| provided that You meet the following conditions: | ||||
|  | ||||
| You must give any other recipients of the Work or Derivative Works a copy of | ||||
| this License; and | ||||
| You must cause any modified files to carry prominent notices stating that You | ||||
| changed the files; and | ||||
| You must retain, in the Source form of any Derivative Works that You distribute, | ||||
| all copyright, patent, trademark, and attribution notices from the Source form | ||||
| of the Work, excluding those notices that do not pertain to any part of the | ||||
| Derivative Works; and | ||||
| If the Work includes a "NOTICE" text file as part of its distribution, then any | ||||
| Derivative Works that You distribute must include a readable copy of the | ||||
| attribution notices contained within such NOTICE file, excluding those notices | ||||
| that do not pertain to any part of the Derivative Works, in at least one of the | ||||
| following places: within a NOTICE text file distributed as part of the | ||||
| Derivative Works; within the Source form or documentation, if provided along | ||||
| with the Derivative Works; or, within a display generated by the Derivative | ||||
| Works, if and wherever such third-party notices normally appear. The contents of | ||||
| the NOTICE file are for informational purposes only and do not modify the | ||||
| License. You may add Your own attribution notices within Derivative Works that | ||||
| You distribute, alongside or as an addendum to the NOTICE text from the Work, | ||||
| provided that such additional attribution notices cannot be construed as | ||||
| modifying the License. | ||||
| You may add Your own copyright statement to Your modifications and may provide | ||||
| additional or different license terms and conditions for use, reproduction, or | ||||
| distribution of Your modifications, or for any such Derivative Works as a whole, | ||||
| provided Your use, reproduction, and distribution of the Work otherwise complies | ||||
| with the conditions stated in this License. | ||||
|  | ||||
| 5. Submission of Contributions. | ||||
|  | ||||
| Unless You explicitly state otherwise, any Contribution intentionally submitted | ||||
| for inclusion in the Work by You to the Licensor shall be under the terms and | ||||
| conditions of this License, without any additional terms or conditions. | ||||
| Notwithstanding the above, nothing herein shall supersede or modify the terms of | ||||
| any separate license agreement you may have executed with Licensor regarding | ||||
| such Contributions. | ||||
|  | ||||
| 6. Trademarks. | ||||
|  | ||||
| This License does not grant permission to use the trade names, trademarks, | ||||
| service marks, or product names of the Licensor, except as required for | ||||
| reasonable and customary use in describing the origin of the Work and | ||||
| reproducing the content of the NOTICE file. | ||||
|  | ||||
| 7. Disclaimer of Warranty. | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, Licensor provides the | ||||
| Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, | ||||
| including, without limitation, any warranties or conditions of TITLE, | ||||
| NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are | ||||
| solely responsible for determining the appropriateness of using or | ||||
| redistributing the Work and assume any risks associated with Your exercise of | ||||
| permissions under this License. | ||||
|  | ||||
| 8. Limitation of Liability. | ||||
|  | ||||
| In no event and under no legal theory, whether in tort (including negligence), | ||||
| contract, or otherwise, unless required by applicable law (such as deliberate | ||||
| and grossly negligent acts) or agreed to in writing, shall any Contributor be | ||||
| liable to You for damages, including any direct, indirect, special, incidental, | ||||
| or consequential damages of any character arising as a result of this License or | ||||
| out of the use or inability to use the Work (including but not limited to | ||||
| damages for loss of goodwill, work stoppage, computer failure or malfunction, or | ||||
| any and all other commercial damages or losses), even if such Contributor has | ||||
| been advised of the possibility of such damages. | ||||
|  | ||||
| 9. Accepting Warranty or Additional Liability. | ||||
|  | ||||
| While redistributing the Work or Derivative Works thereof, You may choose to | ||||
| offer, and charge a fee for, acceptance of support, warranty, indemnity, or | ||||
| other liability obligations and/or rights consistent with this License. However, | ||||
| in accepting such obligations, You may act only on Your own behalf and on Your | ||||
| sole responsibility, not on behalf of any other Contributor, and only if You | ||||
| agree to indemnify, defend, and hold each Contributor harmless for any liability | ||||
| incurred by, or claims asserted against, such Contributor by reason of your | ||||
| accepting any such warranty or additional liability. | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|   | ||||
							
								
								
									
										11
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,4 +1,7 @@ | ||||
| TARGET = lfs | ||||
| TARGET = lfs.a | ||||
| ifneq ($(wildcard test.c main.c),) | ||||
| override TARGET = lfs | ||||
| endif | ||||
|  | ||||
| CC ?= gcc | ||||
| AR ?= ar | ||||
| @@ -22,7 +25,7 @@ ifdef WORD | ||||
| override CFLAGS += -m$(WORD) | ||||
| endif | ||||
| override CFLAGS += -I. | ||||
| override CFLAGS += -std=c99 -Wall -pedantic | ||||
| override CFLAGS += -std=c99 -Wall -pedantic -Wshadow -Wunused-parameter | ||||
|  | ||||
|  | ||||
| all: $(TARGET) | ||||
| @@ -36,7 +39,9 @@ size: $(OBJ) | ||||
| test: test_format test_dirs test_files test_seek test_truncate \ | ||||
| 	test_entries test_interspersed test_alloc test_paths test_attrs \ | ||||
| 	test_move test_orphan test_corrupt | ||||
| 	@rm test.c | ||||
| test_%: tests/test_%.sh | ||||
|  | ||||
| ifdef QUIET | ||||
| 	@./$< | sed -n '/^[-=]/p' | ||||
| else | ||||
| @@ -45,7 +50,7 @@ endif | ||||
|  | ||||
| -include $(DEP) | ||||
|  | ||||
| $(TARGET): $(OBJ) | ||||
| lfs: $(OBJ) | ||||
| 	$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ | ||||
|  | ||||
| %.a: $(OBJ) | ||||
|   | ||||
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							| @@ -146,6 +146,19 @@ The tests assume a Linux environment and can be started with make: | ||||
| make test | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|  | ||||
| The littlefs is provided under the [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html) | ||||
| license. See [LICENSE.md](LICENSE.md) for more information. Contributions to | ||||
| this project are accepted under the same license. | ||||
|  | ||||
| Individual files contain the following tag instead of the full license text. | ||||
|  | ||||
|     SPDX-License-Identifier:    BSD-3-Clause | ||||
|  | ||||
| This enables machine processing of license information based on the SPDX | ||||
| License Identifiers that are here available: http://spdx.org/licenses/ | ||||
|  | ||||
| ## Related projects | ||||
|  | ||||
| [Mbed OS](https://github.com/ARMmbed/mbed-os/tree/master/features/filesystem/littlefs) - | ||||
|   | ||||
| @@ -1,19 +1,8 @@ | ||||
| /* | ||||
|  * Block device emulated on standard files | ||||
|  * | ||||
|  * Copyright (c) 2017 ARM Limited | ||||
|  * | ||||
|  * 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. | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "emubd/lfs_emubd.h" | ||||
|  | ||||
| @@ -27,6 +16,7 @@ | ||||
| #include <unistd.h> | ||||
| #include <assert.h> | ||||
| #include <stdbool.h> | ||||
| #include <inttypes.h> | ||||
|  | ||||
|  | ||||
| // Block device emulated on existing filesystem | ||||
| @@ -96,7 +86,7 @@ int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|     memset(data, 0, size); | ||||
|  | ||||
|     // Read data | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); | ||||
|  | ||||
|     FILE *f = fopen(emu->path, "rb"); | ||||
|     if (!f && errno != ENOENT) { | ||||
| @@ -135,7 +125,7 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|     assert(block < cfg->block_count); | ||||
|  | ||||
|     // Program data | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); | ||||
|  | ||||
|     FILE *f = fopen(emu->path, "r+b"); | ||||
|     if (!f) { | ||||
| @@ -182,7 +172,7 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|     assert(block < cfg->block_count); | ||||
|  | ||||
|     // Erase the block | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block); | ||||
|     struct stat st; | ||||
|     int err = stat(emu->path, &st); | ||||
|     if (err && errno != ENOENT) { | ||||
| @@ -250,4 +240,3 @@ int lfs_emubd_sync(const struct lfs_config *cfg) { | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,19 +1,8 @@ | ||||
| /* | ||||
|  * Block device emulated on standard files | ||||
|  * | ||||
|  * Copyright (c) 2017 ARM Limited | ||||
|  * | ||||
|  * 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. | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_EMUBD_H | ||||
| #define LFS_EMUBD_H | ||||
| @@ -21,6 +10,11 @@ | ||||
| #include "lfs.h" | ||||
| #include "lfs_util.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Config options | ||||
| #ifndef LFS_EMUBD_READ_SIZE | ||||
| @@ -86,4 +80,8 @@ int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block); | ||||
| int lfs_emubd_sync(const struct lfs_config *cfg); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										235
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										235
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -74,12 +74,12 @@ static int lfs_cache_read(lfs_t *lfs, | ||||
|  | ||||
|         // load to cache, first condition can no longer fail | ||||
|         LFS_ASSERT(block < lfs->cfg->block_count); | ||||
|         lfs_size_t size = store ? lfs->cfg->cache_size : lfs->cfg->prog_size; | ||||
|         lfs_size_t nsize = store ? lfs->cfg->cache_size : lfs->cfg->prog_size; | ||||
|         rcache->block = block; | ||||
|         rcache->off = lfs_aligndown(off, size); | ||||
|         rcache->size = size; | ||||
|         rcache->off = lfs_aligndown(off, nsize); | ||||
|         rcache->size = nsize; | ||||
|         int err = lfs->cfg->read(lfs->cfg, rcache->block, | ||||
|                 rcache->off, rcache->buffer, size); | ||||
|                 rcache->off, rcache->buffer, nsize); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -127,6 +127,19 @@ static int lfs_cache_crc(lfs_t *lfs, | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { | ||||
|     // do not zero, cheaper if cache is readonly or only going to be | ||||
|     // written with identical data (during relocates) | ||||
|     (void)lfs; | ||||
|     rcache->block = 0xffffffff; | ||||
| } | ||||
|  | ||||
| static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { | ||||
|     // zero to avoid information leak | ||||
|     memset(pcache->buffer, 0xff, lfs->cfg->prog_size); | ||||
|     pcache->block = 0xffffffff; | ||||
| } | ||||
|  | ||||
| static int lfs_cache_flush(lfs_t *lfs, | ||||
|         lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { | ||||
|     if (pcache->block != 0xffffffff) { | ||||
| @@ -140,7 +153,7 @@ static int lfs_cache_flush(lfs_t *lfs, | ||||
|  | ||||
|         if (validate) { | ||||
|             // check data on disk | ||||
|             rcache->block = 0xffffffff; | ||||
|             lfs_cache_drop(lfs, rcache); | ||||
|             int res = lfs_cache_cmp(lfs, NULL, rcache, pcache->block, | ||||
|                     pcache->off, pcache->buffer, diff); | ||||
|             if (res < 0) { | ||||
| @@ -152,7 +165,7 @@ static int lfs_cache_flush(lfs_t *lfs, | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         pcache->block = 0xffffffff; | ||||
|         lfs_cache_zero(lfs, pcache); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| @@ -234,7 +247,7 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { | ||||
| } | ||||
|  | ||||
| static int lfs_bd_sync(lfs_t *lfs) { | ||||
|     lfs->rcache.block = 0xffffffff; | ||||
|     lfs_cache_drop(lfs, &lfs->rcache); | ||||
|  | ||||
|     int err = lfs_cache_flush(lfs, &lfs->pcache, &lfs->rcache, false); | ||||
|     if (err) { | ||||
| @@ -253,6 +266,7 @@ static int32_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2], | ||||
| static int lfs_fs_relocate(lfs_t *lfs, | ||||
|         const lfs_block_t oldpair[2], lfs_block_t newpair[2]); | ||||
| static int lfs_fs_forceconsistency(lfs_t *lfs); | ||||
| static int lfs_deinit(lfs_t *lfs); | ||||
|  | ||||
|  | ||||
| /// Block allocator /// | ||||
| @@ -294,7 +308,8 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { | ||||
|  | ||||
|         // check if we have looked at all blocks since last ack | ||||
|         if (lfs->free.ack == 0) { | ||||
|             LFS_WARN("No more free space %d", lfs->free.i + lfs->free.off); | ||||
|             LFS_WARN("No more free space %"PRIu32, | ||||
|                     lfs->free.i + lfs->free.off); | ||||
|             return LFS_ERR_NOSPC; | ||||
|         } | ||||
|  | ||||
| @@ -517,7 +532,7 @@ static int lfs_commitattr(lfs_t *lfs, struct lfs_commit *commit, | ||||
|         // special case for moves | ||||
|         return lfs_commitmove(lfs, commit, | ||||
|                 lfs_tagsize(tag), lfs_tagid(tag), | ||||
|                 buffer, NULL);  | ||||
|                 buffer, NULL); | ||||
|     } | ||||
|  | ||||
|     // check if we fit | ||||
| @@ -549,7 +564,7 @@ static int lfs_commitattr(lfs_t *lfs, struct lfs_commit *commit, | ||||
|         for (lfs_off_t i = 0; i < size; i++) { | ||||
|             // rely on caching to make this efficient | ||||
|             uint8_t dat; | ||||
|             int err = lfs_bd_read(lfs, disk->block, disk->off+i, &dat, 1); | ||||
|             err = lfs_bd_read(lfs, disk->block, disk->off+i, &dat, 1); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
| @@ -723,7 +738,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { | ||||
|     // the revision may be valid | ||||
|     int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->rev, 4); | ||||
|     dir->rev = lfs_fromle32(dir->rev); | ||||
|     if (err) { | ||||
|     if (err && err != LFS_ERR_CORRUPT) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
| @@ -752,11 +767,16 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|     // find the block with the most recent revision | ||||
|     uint32_t rev[2]; | ||||
|     for (int i = 0; i < 2; i++) { | ||||
|         int err = lfs_bd_read(lfs, dir->pair[i], 0, &rev[i], sizeof(rev[i])); | ||||
|         if (err) { | ||||
|         int err = lfs_cache_read(lfs, &lfs->pcache, &lfs->rcache, false, | ||||
|                 dir->pair[i], 0, &rev[i], sizeof(rev[i])); | ||||
|         rev[i] = lfs_fromle32(rev[i]); | ||||
|         if (err && err != LFS_ERR_CORRUPT) { | ||||
|             return err; | ||||
|         } | ||||
|         rev[i] = lfs_fromle32(rev[i]); | ||||
|  | ||||
|         if (err == LFS_ERR_CORRUPT) { | ||||
|             rev[i] = rev[(i+1)%2] - 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (lfs_scmp(rev[1], rev[0]) > 0) { | ||||
| @@ -788,6 +808,11 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|             int err = lfs_bd_read(lfs, dir->pair[0], | ||||
|                     off, &tag, sizeof(tag)); | ||||
|             if (err) { | ||||
|                 if (err == LFS_ERR_CORRUPT) { | ||||
|                     // can't continue? | ||||
|                     dir->erased = false; | ||||
|                     break; | ||||
|                 } | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
| @@ -809,9 +834,13 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|             if (lfs_tagtype(tag) == LFS_TYPE_CRC) { | ||||
|                 // check the crc attr | ||||
|                 uint32_t dcrc; | ||||
|                 int err = lfs_bd_read(lfs, dir->pair[0], | ||||
|                 err = lfs_bd_read(lfs, dir->pair[0], | ||||
|                         off+sizeof(tag), &dcrc, sizeof(dcrc)); | ||||
|                 if (err) { | ||||
|                     if (err == LFS_ERR_CORRUPT) { | ||||
|                         dir->erased = false; | ||||
|                         break; | ||||
|                     } | ||||
|                     return err; | ||||
|                 } | ||||
|                 dcrc = lfs_fromle32(dcrc); | ||||
| @@ -834,7 +863,10 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|                 err = lfs_bd_crc(lfs, dir->pair[0], | ||||
|                         off+sizeof(tag), lfs_tagsize(tag), &crc); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
|                     if (err == LFS_ERR_CORRUPT) { | ||||
|                         dir->erased = false; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (lfs_tagid(tag) < 0x3ff && lfs_tagid(tag) >= tempcount) { | ||||
| @@ -846,7 +878,10 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|                     err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag), | ||||
|                             temptail, sizeof(temptail)); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|                         if (err == LFS_ERR_CORRUPT) { | ||||
|                             dir->erased = false; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     lfs_pairfromle32(temptail); | ||||
|                 } else if (lfs_tagsubtype(tag) == LFS_TYPE_GLOBALS) { | ||||
| @@ -854,7 +889,10 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|                     err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag), | ||||
|                             &templocals, sizeof(templocals)); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|                         if (err == LFS_ERR_CORRUPT) { | ||||
|                             dir->erased = false; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (lfs_tagsubtype(tag) == LFS_TYPE_DELETE) { | ||||
|                     LFS_ASSERT(tempcount > 0); | ||||
| @@ -870,6 +908,10 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|                     int res = lfs_bd_cmp(lfs, dir->pair[0], off+sizeof(tag), | ||||
|                             findbuffer, lfs_tagsize(tag)); | ||||
|                     if (res < 0) { | ||||
|                         if (res == LFS_ERR_CORRUPT) { | ||||
|                             dir->erased = false; | ||||
|                             break; | ||||
|                         } | ||||
|                         return res; | ||||
|                     } | ||||
|  | ||||
| @@ -904,7 +946,8 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|         lfs_pairswap(rev); | ||||
|     } | ||||
|  | ||||
|     LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]); | ||||
|     LFS_ERROR("Corrupted dir pair at %"PRIu32" %"PRIu32, | ||||
|             dir->pair[0], dir->pair[1]); | ||||
|     return LFS_ERR_CORRUPT; | ||||
| } | ||||
|  | ||||
| @@ -1051,7 +1094,7 @@ static int lfs_dir_compact(lfs_t *lfs, | ||||
| split: | ||||
|         // commit no longer fits, need to split dir, | ||||
|         // drop caches and create tail | ||||
|         lfs->pcache.block = 0xffffffff; | ||||
|         lfs_cache_drop(lfs, &lfs->pcache); | ||||
|  | ||||
|         if (ack == -1) { | ||||
|             // If we can't fit in this block, we won't fit in next block | ||||
| @@ -1081,15 +1124,16 @@ split: | ||||
|  | ||||
| relocate: | ||||
|         //commit was corrupted | ||||
|         LFS_DEBUG("Bad block at %d", dir->pair[1]); | ||||
|         LFS_DEBUG("Bad block at %"PRIu32, | ||||
|                 dir->pair[1]); | ||||
|  | ||||
|         // drop caches and prepare to relocate block | ||||
|         relocated = true; | ||||
|         lfs->pcache.block = 0xffffffff; | ||||
|         lfs_cache_drop(lfs, &lfs->pcache); | ||||
|  | ||||
|         // can't relocate superblock, filesystem is now frozen | ||||
|         if (lfs_paircmp(oldpair, (const lfs_block_t[2]){0, 1}) == 0) { | ||||
|             LFS_WARN("Superblock %d has become unwritable", oldpair[1]); | ||||
|             LFS_WARN("Superblock %"PRIu32" has become unwritable", oldpair[1]); | ||||
|             return LFS_ERR_CORRUPT; | ||||
|         } | ||||
|  | ||||
| @@ -1108,7 +1152,7 @@ relocate: | ||||
|         lfs_globalzero(&lfs->locals); | ||||
|     } else { | ||||
|         // update references if we relocated | ||||
|         LFS_DEBUG("Relocating %d %d to %d %d", | ||||
|         LFS_DEBUG("Relocating %"PRIu32" %"PRIu32" to %"PRIu32" %"PRIu32, | ||||
|                 oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); | ||||
|         int err = lfs_fs_relocate(lfs, oldpair, dir->pair); | ||||
|         if (err) { | ||||
| @@ -1174,15 +1218,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (!dir->erased) { | ||||
| compact: | ||||
|         // fall back to compaction | ||||
|         lfs->pcache.block = 0xffffffff; | ||||
|         int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } else { | ||||
|     if (dir->erased) { | ||||
|         // try to commit | ||||
|         struct lfs_commit commit = { | ||||
|             .block = dir->pair[0], | ||||
| @@ -1241,6 +1277,14 @@ compact: | ||||
|         // successful commit, update globals | ||||
|         lfs_globalxor(&dir->locals, &lfs->locals); | ||||
|         lfs_globalzero(&lfs->locals); | ||||
|     } else { | ||||
| compact: | ||||
|         // fall back to compaction | ||||
|         lfs_cache_drop(lfs, &lfs->pcache); | ||||
|         int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // update globals that are affected | ||||
| @@ -1583,7 +1627,7 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { | ||||
|                 return LFS_ERR_INVAL; | ||||
|             } | ||||
|  | ||||
|             int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); | ||||
|             err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
| @@ -1752,10 +1796,10 @@ static int lfs_ctzextend(lfs_t *lfs, | ||||
|         } | ||||
|  | ||||
| relocate: | ||||
|         LFS_DEBUG("Bad block at %d", nblock); | ||||
|         LFS_DEBUG("Bad block at %"PRIu32, nblock); | ||||
|  | ||||
|         // just clear cache and try a new block | ||||
|         pcache->block = 0xffffffff; | ||||
|         lfs_cache_drop(lfs, pcache); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1849,7 +1893,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|  | ||||
|         // get next slot and create entry to remember name | ||||
|         file->id = file->m.count; | ||||
|         int err = lfs_dir_commit(lfs, &file->m, | ||||
|         err = lfs_dir_commit(lfs, &file->m, | ||||
|                 LFS_MKATTR(LFS_TYPE_REG, file->id, path, nlen, | ||||
|                 LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id, NULL, 0, | ||||
|                 NULL))); | ||||
| @@ -1902,7 +1946,6 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|     } | ||||
|  | ||||
|     // allocate buffer if needed | ||||
|     file->cache.block = 0xffffffff; | ||||
|     if (file->cfg->buffer) { | ||||
|         file->cache.buffer = file->cfg->buffer; | ||||
|     } else { | ||||
| @@ -1913,6 +1956,9 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // zero to avoid information leak | ||||
|     lfs_cache_zero(lfs, &file->cache); | ||||
|  | ||||
|     if (lfs_tagtype(tag) == LFS_TYPE_INLINESTRUCT) { | ||||
|         // load inline files | ||||
|         file->ctz.head = 0xfffffffe; | ||||
| @@ -2009,7 +2055,7 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | ||||
|         file->cache.block = lfs->pcache.block; | ||||
|         file->cache.off = lfs->pcache.off; | ||||
|         file->cache.size = lfs->pcache.size; | ||||
|         lfs->pcache.block = 0xffffffff; | ||||
|         lfs_cache_zero(lfs, &lfs->pcache); | ||||
|  | ||||
|         file->block = nblock; | ||||
|         return 0; | ||||
| @@ -2036,7 +2082,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||
|                 .pos = file->pos, | ||||
|                 .cache = lfs->rcache, | ||||
|             }; | ||||
|             lfs->rcache.block = 0xffffffff; | ||||
|             lfs_cache_drop(lfs, &lfs->rcache); | ||||
|  | ||||
|             while (file->pos < file->ctz.size) { | ||||
|                 // copy over a byte at a time, leave it up to caching | ||||
| @@ -2054,8 +2100,8 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||
|  | ||||
|                 // keep our reference to the rcache in sync | ||||
|                 if (lfs->rcache.block != 0xffffffff) { | ||||
|                     orig.cache.block = 0xffffffff; | ||||
|                     lfs->rcache.block = 0xffffffff; | ||||
|                     lfs_cache_drop(lfs, &orig.cache); | ||||
|                     lfs_cache_drop(lfs, &lfs->rcache); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -2073,7 +2119,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||
|                 break; | ||||
|  | ||||
| relocate: | ||||
|                 LFS_DEBUG("Bad block at %d", file->block); | ||||
|                 LFS_DEBUG("Bad block at %"PRIu32, file->block); | ||||
|                 err = lfs_file_relocate(lfs, file); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
| @@ -2123,7 +2169,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | ||||
|  | ||||
|             // commit file data and attributes | ||||
|             lfs_ctztole32(&file->ctz); | ||||
|             int err = lfs_dir_commit(lfs, &file->m, | ||||
|             err = lfs_dir_commit(lfs, &file->m, | ||||
|                     LFS_MKATTR(type, file->id, buffer, size, | ||||
|                     LFS_MKATTR(LFS_FROM_ATTRS, file->id, file->cfg->attrs, 0, | ||||
|                     NULL))); | ||||
| @@ -2284,7 +2330,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
|                     } | ||||
|  | ||||
|                     // mark cache as dirty since we may have read data into it | ||||
|                     file->cache.block = 0xffffffff; | ||||
|                     lfs_cache_zero(lfs, &file->cache); | ||||
|                 } | ||||
|  | ||||
|                 // extend file with new blocks | ||||
| @@ -2482,7 +2528,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|         } | ||||
|         lfs_pairfromle32(pair); | ||||
|  | ||||
|         int err = lfs_dir_fetch(lfs, &dir, pair); | ||||
|         err = lfs_dir_fetch(lfs, &dir, pair); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2504,7 +2550,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|     } | ||||
|  | ||||
|     if (lfs_tagtype(tag) == LFS_TYPE_DIR) { | ||||
|         int err = lfs_fs_pred(lfs, dir.pair, &cwd); | ||||
|         err = lfs_fs_pred(lfs, dir.pair, &cwd); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2571,7 +2617,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|             lfs_pairfromle32(prevpair); | ||||
|  | ||||
|             // must be empty before removal | ||||
|             int err = lfs_dir_fetch(lfs, &prevdir, prevpair); | ||||
|             err = lfs_dir_fetch(lfs, &prevdir, prevpair); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
| @@ -2616,7 +2662,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     } | ||||
|  | ||||
|     if (prevtag != LFS_ERR_NOENT && lfs_tagtype(prevtag) == LFS_TYPE_DIR) { | ||||
|         int err = lfs_fs_pred(lfs, prevdir.pair, &newcwd); | ||||
|         err = lfs_fs_pred(lfs, prevdir.pair, &newcwd); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2697,6 +2743,7 @@ static inline void lfs_superblocktole32(lfs_superblock_t *superblock) { | ||||
|  | ||||
| static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs->cfg = cfg; | ||||
|     int err = 0; | ||||
|  | ||||
|     // check that block size is a multiple of cache size is a multiple | ||||
|     // of prog and read sizes | ||||
| @@ -2709,27 +2756,31 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|             <= lfs->cfg->block_size); | ||||
|  | ||||
|     // setup read cache | ||||
|     lfs->rcache.block = 0xffffffff; | ||||
|     if (lfs->cfg->read_buffer) { | ||||
|         lfs->rcache.buffer = lfs->cfg->read_buffer; | ||||
|     } else { | ||||
|         lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size); | ||||
|         if (!lfs->rcache.buffer) { | ||||
|             return LFS_ERR_NOMEM; | ||||
|             err = LFS_ERR_NOMEM; | ||||
|             goto cleanup; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // setup program cache | ||||
|     lfs->pcache.block = 0xffffffff; | ||||
|     if (lfs->cfg->prog_buffer) { | ||||
|         lfs->pcache.buffer = lfs->cfg->prog_buffer; | ||||
|     } else { | ||||
|         lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size); | ||||
|         if (!lfs->pcache.buffer) { | ||||
|             return LFS_ERR_NOMEM; | ||||
|             err = LFS_ERR_NOMEM; | ||||
|             goto cleanup; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // zero to avoid information leaks | ||||
|     lfs_cache_zero(lfs, &lfs->rcache); | ||||
|     lfs_cache_zero(lfs, &lfs->pcache); | ||||
|  | ||||
|     // setup lookahead, must be multiple of 32-bits | ||||
|     LFS_ASSERT(lfs->cfg->lookahead % 32 == 0); | ||||
|     LFS_ASSERT(lfs->cfg->lookahead > 0); | ||||
| @@ -2738,7 +2789,8 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     } else { | ||||
|         lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead/8); | ||||
|         if (!lfs->free.buffer) { | ||||
|             return LFS_ERR_NOMEM; | ||||
|             err = LFS_ERR_NOMEM; | ||||
|             goto cleanup; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -2773,6 +2825,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs_globalzero(&lfs->locals); | ||||
|  | ||||
|     return 0; | ||||
|  | ||||
| cleanup: | ||||
|     lfs_deinit(lfs); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| static int lfs_deinit(lfs_t *lfs) { | ||||
| @@ -2809,19 +2865,19 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs_mdir_t dir; | ||||
|     err = lfs_dir_alloc(lfs, &dir); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     // write root directory | ||||
|     lfs_mdir_t root; | ||||
|     err = lfs_dir_alloc(lfs, &root); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     err = lfs_dir_commit(lfs, &root, NULL); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     lfs->root[0] = root.pair[0]; | ||||
| @@ -2850,16 +2906,18 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs_pairfromle32(lfs->root); | ||||
|     lfs_superblockfromle32(&superblock); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     // sanity check that fetch works | ||||
|     err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     return lfs_deinit(lfs); | ||||
| cleanup: | ||||
|     lfs_deinit(lfs); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
| @@ -2878,7 +2936,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs_mdir_t superdir; | ||||
|     err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); | ||||
|     if (err) { | ||||
|         return err; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     lfs_superblock_t superblock; | ||||
| @@ -2886,7 +2944,8 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|             LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)), | ||||
|             &superblock); | ||||
|     if (res < 0) { | ||||
|         return res; | ||||
|         err = res; | ||||
|         goto cleanup; | ||||
|     } | ||||
|     lfs_superblockfromle32(&superblock); | ||||
|  | ||||
| @@ -2899,24 +2958,28 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     uint16_t minor_version = (0xffff & (superblock.version >>  0)); | ||||
|     if ((major_version != LFS_DISK_VERSION_MAJOR || | ||||
|          minor_version > LFS_DISK_VERSION_MINOR)) { | ||||
|         LFS_ERROR("Invalid version %d.%d", major_version, minor_version); | ||||
|         return LFS_ERR_INVAL; | ||||
|         LFS_ERROR("Invalid version %"PRIu32".%"PRIu32, | ||||
|                 major_version, minor_version); | ||||
|         err = LFS_ERR_INVAL; | ||||
|         goto cleanup; | ||||
|     } | ||||
|  | ||||
|     res = lfs_dir_get(lfs, &superdir, 0x7ffff000, | ||||
|             LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, sizeof(lfs->root)), | ||||
|             &lfs->root); | ||||
|     if (res < 0) { | ||||
|         return res; | ||||
|         err = res; | ||||
|         goto cleanup; | ||||
|     } | ||||
|     lfs_pairfromle32(lfs->root); | ||||
|  | ||||
|     // check superblock configuration | ||||
|     if (superblock.attr_max) { | ||||
|         if (superblock.attr_max > lfs->attr_max) { | ||||
|             LFS_ERROR("Unsupported attr_max (%d > %d)", | ||||
|             LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", | ||||
|                     superblock.attr_max, lfs->attr_max); | ||||
|             return LFS_ERR_INVAL; | ||||
|             err = LFS_ERR_INVAL; | ||||
|             goto cleanup; | ||||
|         } | ||||
|  | ||||
|         lfs->attr_max = superblock.attr_max; | ||||
| @@ -2924,9 +2987,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|  | ||||
|     if (superblock.name_max) { | ||||
|         if (superblock.name_max > lfs->name_max) { | ||||
|             LFS_ERROR("Unsupported name_max (%d > %d)", | ||||
|             LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", | ||||
|                     superblock.name_max, lfs->name_max); | ||||
|             return LFS_ERR_INVAL; | ||||
|             err = LFS_ERR_INVAL; | ||||
|             goto cleanup; | ||||
|         } | ||||
|  | ||||
|         lfs->name_max = superblock.name_max; | ||||
| @@ -2934,9 +2998,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|  | ||||
|     if (superblock.inline_max) { | ||||
|         if (superblock.inline_max > lfs->inline_max) { | ||||
|             LFS_ERROR("Unsupported inline_max (%d > %d)", | ||||
|             LFS_ERROR("Unsupported inline_max (%"PRIu32" > %"PRIu32")", | ||||
|                     superblock.inline_max, lfs->inline_max); | ||||
|             return LFS_ERR_INVAL; | ||||
|             err = LFS_ERR_INVAL; | ||||
|             goto cleanup; | ||||
|         } | ||||
|  | ||||
|         lfs->inline_max = superblock.inline_max; | ||||
| @@ -2945,9 +3010,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     // scan for any global updates | ||||
|     lfs_mdir_t dir = {.tail = {0, 1}}; | ||||
|     while (!lfs_pairisnull(dir.tail)) { | ||||
|         int err = lfs_dir_fetch(lfs, &dir, dir.tail); | ||||
|         err = lfs_dir_fetch(lfs, &dir, dir.tail); | ||||
|         if (err) { | ||||
|             return err; | ||||
|             err = LFS_ERR_INVAL; | ||||
|             goto cleanup; | ||||
|         } | ||||
|  | ||||
|         // xor together indirect deletes | ||||
| @@ -2959,13 +3025,17 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs_globalxor(&lfs->globals, &lfs->locals); | ||||
|     lfs_globalzero(&lfs->locals); | ||||
|     if (!lfs_pairisnull(lfs->globals.s.movepair)) { | ||||
|         LFS_DEBUG("Found move %d %d %d", | ||||
|         LFS_DEBUG("Found move %"PRIu32" %"PRIu32" %"PRIu32, | ||||
|                 lfs->globals.s.movepair[0], | ||||
|                 lfs->globals.s.movepair[1], | ||||
|                 lfs->globals.s.moveid); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
|  | ||||
| cleanup: | ||||
|     lfs_unmount(lfs); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int lfs_unmount(lfs_t *lfs) { | ||||
| @@ -3009,7 +3079,7 @@ int lfs_fs_traverse(lfs_t *lfs, | ||||
|             lfs_ctzfromle32(&ctz); | ||||
|  | ||||
|             if (lfs_tagtype(tag) == LFS_TYPE_CTZSTRUCT) { | ||||
|                 int err = lfs_ctztraverse(lfs, &lfs->rcache, NULL, | ||||
|                 err = lfs_ctztraverse(lfs, &lfs->rcache, NULL, | ||||
|                         ctz.head, ctz.size, cb, data); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
| @@ -3099,7 +3169,8 @@ static int lfs_fs_relocate(lfs_t *lfs, | ||||
|         const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { | ||||
|     // update internal root | ||||
|     if (lfs_paircmp(oldpair, lfs->root) == 0) { | ||||
|         LFS_DEBUG("Relocating root %d %d", newpair[0], newpair[1]); | ||||
|         LFS_DEBUG("Relocating root %"PRIu32" %"PRIu32, | ||||
|                 newpair[0], newpair[1]); | ||||
|         lfs->root[0] = newpair[0]; | ||||
|         lfs->root[1] = newpair[1]; | ||||
|     } | ||||
| @@ -3144,7 +3215,7 @@ static int lfs_fs_relocate(lfs_t *lfs, | ||||
|         // just replace bad pair, no desync can occur | ||||
|         parent.tail[0] = newpair[0]; | ||||
|         parent.tail[1] = newpair[1]; | ||||
|         int err = lfs_dir_commit(lfs, &parent, | ||||
|         err = lfs_dir_commit(lfs, &parent, | ||||
|                 LFS_MKATTR(LFS_TYPE_TAIL + parent.split, 0x3ff, | ||||
|                     parent.tail, sizeof(parent.tail), | ||||
|                 NULL)); | ||||
| @@ -3158,7 +3229,7 @@ static int lfs_fs_relocate(lfs_t *lfs, | ||||
|  | ||||
| static int lfs_fs_forceconsistency(lfs_t *lfs) { | ||||
|     if (!lfs->globals.s.deorphaned) { | ||||
|         LFS_DEBUG("Found orphans %d", | ||||
|         LFS_DEBUG("Found orphans %"PRIu32, | ||||
|                 lfs->globals.s.deorphaned); | ||||
|  | ||||
|         // Fix any orphans | ||||
| @@ -3183,7 +3254,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { | ||||
|  | ||||
|                 if (tag == LFS_ERR_NOENT) { | ||||
|                     // we are an orphan | ||||
|                     LFS_DEBUG("Fixing orphan %d %d", | ||||
|                     LFS_DEBUG("Fixing orphan %"PRIu32" %"PRIu32, | ||||
|                             pdir.tail[0], pdir.tail[1]); | ||||
|  | ||||
|                     pdir.tail[0] = dir.tail[0]; | ||||
| @@ -3208,7 +3279,8 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { | ||||
|  | ||||
|                 if (!lfs_pairsync(pair, pdir.tail)) { | ||||
|                     // we have desynced | ||||
|                     LFS_DEBUG("Fixing half-orphan %d %d", pair[0], pair[1]); | ||||
|                     LFS_DEBUG("Fixing half-orphan %"PRIu32" %"PRIu32, | ||||
|                             pair[0], pair[1]); | ||||
|  | ||||
|                     pdir.tail[0] = pair[0]; | ||||
|                     pdir.tail[1] = pair[1]; | ||||
| @@ -3233,7 +3305,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { | ||||
|  | ||||
|     if (lfs->globals.s.moveid != 0x3ff) { | ||||
|         // Fix bad moves | ||||
|         LFS_DEBUG("Fixing move %d %d %d", | ||||
|         LFS_DEBUG("Fixing move %"PRIu32" %"PRIu32" %"PRIu32, | ||||
|                 lfs->globals.s.movepair[0], | ||||
|                 lfs->globals.s.movepair[1], | ||||
|                 lfs->globals.s.moveid); | ||||
| @@ -3291,6 +3363,7 @@ int lfs_fs_setattr(lfs_t *lfs, | ||||
| } | ||||
|  | ||||
| static int lfs_fs_size_count(void *p, lfs_block_t block) { | ||||
|     (void)block; | ||||
|     lfs_size_t *size = p; | ||||
|     *size += 1; | ||||
|     return 0; | ||||
|   | ||||
							
								
								
									
										25
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -1,19 +1,8 @@ | ||||
| /* | ||||
|  * The little filesystem | ||||
|  * | ||||
|  * Copyright (c) 2017 ARM Limited | ||||
|  * | ||||
|  * 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. | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_H | ||||
| #define LFS_H | ||||
| @@ -21,6 +10,11 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /// Version info /// | ||||
|  | ||||
| @@ -481,7 +475,6 @@ int lfs_setattr(lfs_t *lfs, const char *path, | ||||
| int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|         const char *path, int flags); | ||||
|  | ||||
|  | ||||
| // Open a file with extra configuration | ||||
| // | ||||
| // The mode that the file is opened in is determined by the flags, which | ||||
| @@ -653,4 +646,8 @@ int lfs_fs_setattr(lfs_t *lfs, | ||||
|         uint8_t type, const void *buffer, lfs_size_t size); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										15
									
								
								lfs_util.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								lfs_util.c
									
									
									
									
									
								
							| @@ -1,19 +1,8 @@ | ||||
| /* | ||||
|  * lfs util functions | ||||
|  * | ||||
|  * Copyright (c) 2017 ARM Limited | ||||
|  * | ||||
|  * 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. | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #include "lfs_util.h" | ||||
|  | ||||
|   | ||||
							
								
								
									
										28
									
								
								lfs_util.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								lfs_util.h
									
									
									
									
									
								
							| @@ -1,19 +1,8 @@ | ||||
| /* | ||||
|  * lfs utility functions | ||||
|  * | ||||
|  * Copyright (c) 2017 ARM Limited | ||||
|  * | ||||
|  * 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. | ||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||
|  * SPDX-License-Identifier: BSD-3-Clause | ||||
|  */ | ||||
| #ifndef LFS_UTIL_H | ||||
| #define LFS_UTIL_H | ||||
| @@ -34,6 +23,7 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include <inttypes.h> | ||||
|  | ||||
| #ifndef LFS_NO_MALLOC | ||||
| #include <stdlib.h> | ||||
| @@ -45,6 +35,11 @@ | ||||
| #include <stdio.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Macros, may be replaced by system specific wrappers. Arguments to these | ||||
| // macros must not have side-effects as the macros can be removed for a smaller | ||||
| @@ -199,6 +194,7 @@ static inline void *lfs_malloc(size_t size) { | ||||
| #ifndef LFS_NO_MALLOC | ||||
|     return malloc(size); | ||||
| #else | ||||
|     (void)size; | ||||
|     return NULL; | ||||
| #endif | ||||
| } | ||||
| @@ -207,9 +203,15 @@ static inline void *lfs_malloc(size_t size) { | ||||
| static inline void lfs_free(void *p) { | ||||
| #ifndef LFS_NO_MALLOC | ||||
|     free(p); | ||||
| #else | ||||
|     (void)p; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| #endif | ||||
|   | ||||
| @@ -30,7 +30,7 @@ TEST | ||||
|  | ||||
| w_test() { | ||||
| tests/test.py << TEST | ||||
|     lfs_size_t size = $1; | ||||
|     size = $1; | ||||
|     lfs_size_t chunk = 31; | ||||
|     srand(0); | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
| @@ -50,7 +50,7 @@ TEST | ||||
|  | ||||
| r_test() { | ||||
| tests/test.py << TEST | ||||
|     lfs_size_t size = $1; | ||||
|     size = $1; | ||||
|     lfs_size_t chunk = 29; | ||||
|     srand(0); | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|   | ||||
| @@ -153,7 +153,7 @@ tests/test.py << TEST | ||||
|     lfs_file_read(&lfs, &file[0], buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_size_t size = lfs_file_size(&lfs, &file[0]); | ||||
|     size = lfs_file_size(&lfs, &file[0]); | ||||
|     lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
| @@ -202,7 +202,7 @@ tests/test.py << TEST | ||||
|     lfs_file_read(&lfs, &file[0], buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_size_t size = lfs_file_size(&lfs, &file[0]); | ||||
|     size = lfs_file_size(&lfs, &file[0]); | ||||
|     lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
| @@ -243,7 +243,7 @@ tests/test.py << TEST | ||||
|     lfs_file_read(&lfs, &file[0], buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_size_t size = lfs_file_size(&lfs, &file[0]); | ||||
|     size = lfs_file_size(&lfs, &file[0]); | ||||
|     lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
| @@ -286,7 +286,7 @@ tests/test.py << TEST | ||||
|     lfs_file_read(&lfs, &file[0], buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs_size_t size = lfs_file_size(&lfs, &file[0]); | ||||
|     size = lfs_file_size(&lfs, &file[0]); | ||||
|     lfs_file_seek(&lfs, &file[0], 0, LFS_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user