mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Compare commits
	
		
			36 Commits
		
	
	
		
			v2.2.1
			...
			crc-rework
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 97b5d04bf4 | ||
|  | 7535795a44 | ||
|  | 01a3b1f5f7 | ||
|  | 288a5cbc8d | ||
|  | 5783eea0de | ||
|  | 2bb523421e | ||
|  | 7388b2938a | ||
|  | ce425a56c3 | ||
|  | a99a93fb27 | ||
|  | 45afded784 | ||
|  | 00a9ba7826 | ||
|  | fc6988c7c3 | ||
|  | d0f055d321 | ||
|  | b9fa33f9bc | ||
|  | 2efebf8e9b | ||
|  | 754b4c3cda | ||
|  | 584eb26efc | ||
|  | 008ebc37df | ||
|  | 66272067ab | ||
|  | e273a82679 | ||
|  | 1dc6ae94b9 | ||
|  | 817ef02d24 | ||
|  | b8dcf10974 | ||
|  | 0aba71d0d6 | ||
|  | 0ea2871e24 | ||
|  | d04c1392c0 | ||
|  | f215027fd4 | ||
|  | 1ae4b36f2a | ||
|  | 480cdd9f81 | ||
|  | 6303558aee | ||
|  | 4bd653dd00 | ||
|  | 8e6826c4e2 | ||
|  | 10ac6b9cf0 | ||
|  | 87a2cb0e41 | ||
|  | 6d0ec5e851 | ||
|  | 64f70f51b0 | 
							
								
								
									
										32
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -208,6 +208,38 @@ jobs: | ||||
|     script: | ||||
|       - make test TFLAGS+="-k --valgrind" | ||||
|  | ||||
|   # test compilation in read-only mode | ||||
|   - stage: test | ||||
|     env: | ||||
|       - NAME=littlefs-readonly | ||||
|       - CC="arm-linux-gnueabi-gcc --static -mthumb" | ||||
|       - CFLAGS="-Werror -DLFS_READONLY" | ||||
|     if: branch !~ -prefix$ | ||||
|     install: | ||||
|       - *install-common | ||||
|       - sudo apt-get install | ||||
|             gcc-arm-linux-gnueabi | ||||
|             libc6-dev-armel-cross | ||||
|       - arm-linux-gnueabi-gcc --version | ||||
|     # report-size will compile littlefs and report the size | ||||
|     script: [*report-size] | ||||
|  | ||||
|   # test compilation in thread-safe mode | ||||
|   - stage: test | ||||
|     env: | ||||
|       - NAME=littlefs-threadsafe | ||||
|       - CC="arm-linux-gnueabi-gcc --static -mthumb" | ||||
|       - CFLAGS="-Werror -DLFS_THREADSAFE" | ||||
|     if: branch !~ -prefix$ | ||||
|     install: | ||||
|       - *install-common | ||||
|       - sudo apt-get install | ||||
|             gcc-arm-linux-gnueabi | ||||
|             libc6-dev-armel-cross | ||||
|       - arm-linux-gnueabi-gcc --version | ||||
|     # report-size will compile littlefs and report the size | ||||
|     script: [*report-size] | ||||
|  | ||||
|   # self-host with littlefs-fuse for fuzz test | ||||
|   - stage: test | ||||
|     env: | ||||
|   | ||||
| @@ -221,6 +221,11 @@ License Identifiers that are here available: http://spdx.org/licenses/ | ||||
| - [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would | ||||
|   want this, but it is handy for demos.  You can see it in action | ||||
|   [here][littlefs-js-demo]. | ||||
|    | ||||
| - [littlefs-python] - A Python wrapper for littlefs. The project allows you | ||||
|   to create images of the filesystem on your PC. Check if littlefs will fit | ||||
|   your needs, create images for a later download to the target memory or | ||||
|   inspect the content of a binary image of the target memory. | ||||
|  | ||||
| - [mklfs] - A command line tool built by the [Lua RTOS] guys for making | ||||
|   littlefs images from a host PC. Supports Windows, Mac OS, and Linux. | ||||
| @@ -250,3 +255,4 @@ License Identifiers that are here available: http://spdx.org/licenses/ | ||||
| [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html | ||||
| [SPIFFS]: https://github.com/pellepl/spiffs | ||||
| [Dhara]: https://github.com/dlbeer/dhara | ||||
| [littlefs-python]: https://pypi.org/project/littlefs-python/ | ||||
|   | ||||
| @@ -80,11 +80,6 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|     LFS_ASSERT(size % cfg->read_size == 0); | ||||
|     LFS_ASSERT(block < cfg->block_count); | ||||
|  | ||||
|     // zero for reproducability (in case file is truncated) | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
|         memset(buffer, bd->cfg->erase_value, size); | ||||
|     } | ||||
|  | ||||
|     // read | ||||
|     off_t res1 = lseek(bd->fd, | ||||
|             (off_t)block*cfg->block_size + (off_t)off, SEEK_SET); | ||||
| @@ -101,6 +96,11 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // file truncated? zero for reproducability | ||||
|     if ((lfs_size_t)res2 < size) { | ||||
|         memset((uint8_t*)buffer + res2, 0, size-res2); | ||||
|     } | ||||
|  | ||||
|     LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0); | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -32,11 +32,8 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // zero for reproducability? | ||||
|     if (bd->cfg->erase_value != -1) { | ||||
|         memset(bd->buffer, bd->cfg->erase_value, | ||||
|                 cfg->block_size * cfg->block_count); | ||||
|     } | ||||
|     // zero for reproducability (this matches filebd) | ||||
|     memset(bd->buffer, 0, cfg->block_size * cfg->block_count); | ||||
|  | ||||
|     LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0); | ||||
|     return 0; | ||||
|   | ||||
| @@ -207,7 +207,7 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         bd->power_cycles -= 1; | ||||
|         if (bd->power_cycles == 0) { | ||||
|             // sync to make sure we persist the last changes | ||||
|             assert(lfs_testbd_rawsync(cfg) == 0); | ||||
|             LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); | ||||
|             // simulate power loss | ||||
|             exit(33); | ||||
|         } | ||||
| @@ -254,7 +254,7 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|         bd->power_cycles -= 1; | ||||
|         if (bd->power_cycles == 0) { | ||||
|             // sync to make sure we persist the last changes | ||||
|             assert(lfs_testbd_rawsync(cfg) == 0); | ||||
|             LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); | ||||
|             // simulate power loss | ||||
|             exit(33); | ||||
|         } | ||||
|   | ||||
							
								
								
									
										42
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -9,6 +9,7 @@ | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "lfs_util.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| @@ -21,7 +22,7 @@ extern "C" | ||||
| // Software library version | ||||
| // Major (top-nibble), incremented on backwards incompatible changes | ||||
| // Minor (bottom-nibble), incremented on feature additions | ||||
| #define LFS_VERSION 0x00020002 | ||||
| #define LFS_VERSION 0x00020003 | ||||
| #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) | ||||
| #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >>  0)) | ||||
|  | ||||
| @@ -112,6 +113,8 @@ enum lfs_type { | ||||
|     LFS_TYPE_SOFTTAIL       = 0x600, | ||||
|     LFS_TYPE_HARDTAIL       = 0x601, | ||||
|     LFS_TYPE_MOVESTATE      = 0x7ff, | ||||
|     LFS_TYPE_COMMITCRC      = 0x502, | ||||
|     LFS_TYPE_NPROGCRC       = 0x5ff, | ||||
|  | ||||
|     // internal chip sources | ||||
|     LFS_FROM_NOOP           = 0x000, | ||||
| @@ -123,20 +126,25 @@ enum lfs_type { | ||||
| enum lfs_open_flags { | ||||
|     // open flags | ||||
|     LFS_O_RDONLY = 1,         // Open a file as read only | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_O_WRONLY = 2,         // Open a file as write only | ||||
|     LFS_O_RDWR   = 3,         // Open a file as read and write | ||||
|     LFS_O_CREAT  = 0x0100,    // Create a file if it does not exist | ||||
|     LFS_O_EXCL   = 0x0200,    // Fail if a file already exists | ||||
|     LFS_O_TRUNC  = 0x0400,    // Truncate the existing file to zero size | ||||
|     LFS_O_APPEND = 0x0800,    // Move to end of file on every write | ||||
| #endif | ||||
|  | ||||
|     // internally used flags | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_F_DIRTY   = 0x010000, // File does not match storage | ||||
|     LFS_F_WRITING = 0x020000, // File has been written since last flush | ||||
| #endif | ||||
|     LFS_F_READING = 0x040000, // File has been read since last flush | ||||
|     LFS_F_ERRED   = 0x080000, // An error occured during write | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_F_ERRED   = 0x080000, // An error occurred during write | ||||
| #endif | ||||
|     LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry | ||||
|     LFS_F_OPENED  = 0x200000, // File has been opened | ||||
| }; | ||||
|  | ||||
| // File seek flags | ||||
| @@ -174,6 +182,16 @@ struct lfs_config { | ||||
|     // are propogated to the user. | ||||
|     int (*sync)(const struct lfs_config *c); | ||||
|  | ||||
| #ifdef LFS_THREADSAFE | ||||
|     // Lock the underlying block device. Negative error codes | ||||
|     // are propogated to the user. | ||||
|     int (*lock)(const struct lfs_config *c); | ||||
|  | ||||
|     // Unlock the underlying block device. Negative error codes | ||||
|     // are propogated to the user. | ||||
|     int (*unlock)(const struct lfs_config *c); | ||||
| #endif | ||||
|  | ||||
|     // Minimum size of a block read. All read operations will be a | ||||
|     // multiple of this value. | ||||
|     lfs_size_t read_size; | ||||
| @@ -399,6 +417,7 @@ typedef struct lfs { | ||||
|  | ||||
| /// Filesystem functions /// | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Format a block device with the littlefs | ||||
| // | ||||
| // Requires a littlefs object and config struct. This clobbers the littlefs | ||||
| @@ -407,6 +426,7 @@ typedef struct lfs { | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *config); | ||||
| #endif | ||||
|  | ||||
| // Mounts a littlefs | ||||
| // | ||||
| @@ -426,12 +446,15 @@ int lfs_unmount(lfs_t *lfs); | ||||
|  | ||||
| /// General operations /// | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Removes a file or directory | ||||
| // | ||||
| // If removing a directory, the directory must be empty. | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_remove(lfs_t *lfs, const char *path); | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Rename or move a file or directory | ||||
| // | ||||
| // If the destination exists, it must match the source in type. | ||||
| @@ -439,6 +462,7 @@ int lfs_remove(lfs_t *lfs, const char *path); | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); | ||||
| #endif | ||||
|  | ||||
| // Find info about a file or directory | ||||
| // | ||||
| @@ -461,6 +485,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); | ||||
| lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | ||||
|         uint8_t type, void *buffer, lfs_size_t size); | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Set custom attributes | ||||
| // | ||||
| // Custom attributes are uniquely identified by an 8-bit type and limited | ||||
| @@ -470,13 +495,16 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_setattr(lfs_t *lfs, const char *path, | ||||
|         uint8_t type, const void *buffer, lfs_size_t size); | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Removes a custom attribute | ||||
| // | ||||
| // If an attribute is not found, nothing happens. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /// File operations /// | ||||
| @@ -525,6 +553,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); | ||||
| lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
|         void *buffer, lfs_size_t size); | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Write data to file | ||||
| // | ||||
| // Takes a buffer and size indicating the data to write. The file will not | ||||
| @@ -533,6 +562,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
| // Returns the number of bytes written, or a negative error code on failure. | ||||
| lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
|         const void *buffer, lfs_size_t size); | ||||
| #endif | ||||
|  | ||||
| // Change the position of the file | ||||
| // | ||||
| @@ -541,10 +571,12 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
| lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | ||||
|         lfs_soff_t off, int whence); | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Truncates the size of the file to the specified size | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); | ||||
| #endif | ||||
|  | ||||
| // Return the position of the file | ||||
| // | ||||
| @@ -567,10 +599,12 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); | ||||
|  | ||||
| /// Directory operations /// | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| // Create a directory | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_mkdir(lfs_t *lfs, const char *path); | ||||
| #endif | ||||
|  | ||||
| // Open a directory | ||||
| // | ||||
| @@ -632,6 +666,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| #ifdef LFS_MIGRATE | ||||
| // Attempts to migrate a previous version of littlefs | ||||
| // | ||||
| @@ -646,6 +681,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|   | ||||
| @@ -24,6 +24,7 @@ TAG_TYPES = { | ||||
|     'gstate':       (0x700, 0x700), | ||||
|     'movestate':    (0x7ff, 0x7ff), | ||||
|     'crc':          (0x700, 0x500), | ||||
|     'nprogcrc':     (0x7ff, 0x5ff), | ||||
| } | ||||
|  | ||||
| class Tag: | ||||
| @@ -99,7 +100,16 @@ class Tag: | ||||
|         return struct.unpack('b', struct.pack('B', self.chunk))[0] | ||||
|  | ||||
|     def is_(self, type): | ||||
|         return (self.type & TAG_TYPES[type][0]) == TAG_TYPES[type][1] | ||||
|         try: | ||||
|             if ' ' in type: | ||||
|                 type1, type3 = type.split() | ||||
|                 return (self.is_(type1) and | ||||
|                     (self.type & ~TAG_TYPES[type1][0]) == int(type3, 0)) | ||||
|  | ||||
|             return self.type == int(type, 0) | ||||
|  | ||||
|         except (ValueError, KeyError): | ||||
|             return (self.type & TAG_TYPES[type][0]) == TAG_TYPES[type][1] | ||||
|  | ||||
|     def mkmask(self): | ||||
|         return Tag( | ||||
| @@ -109,14 +119,20 @@ class Tag: | ||||
|  | ||||
|     def chid(self, nid): | ||||
|         ntag = Tag(self.type, nid, self.size) | ||||
|         if hasattr(self, 'off'):  ntag.off  = self.off | ||||
|         if hasattr(self, 'data'): ntag.data = self.data | ||||
|         if hasattr(self, 'crc'):  ntag.crc  = self.crc | ||||
|         if hasattr(self, 'off'):    ntag.off    = self.off | ||||
|         if hasattr(self, 'data'):   ntag.data   = self.data | ||||
|         if hasattr(self, 'crc'):    ntag.crc    = self.crc | ||||
|         if hasattr(self, 'erased'): ntag.erased = self.erased | ||||
|         return ntag | ||||
|  | ||||
|     def typerepr(self): | ||||
|         if self.is_('crc') and getattr(self, 'crc', 0xffffffff) != 0xffffffff: | ||||
|             return 'crc (bad)' | ||||
|         if (self.is_('crc') and not self.is_('nprogcrc') and | ||||
|                 getattr(self, 'crc', 0xffffffff) != 0xffffffff): | ||||
|             crc_status = ' (bad)' | ||||
|         elif self.is_('nprogcrc') and getattr(self, 'erased', False): | ||||
|             crc_status = ' (era)' | ||||
|         else: | ||||
|             crc_status = '' | ||||
|  | ||||
|         reverse_types = {v: k for k, v in TAG_TYPES.items()} | ||||
|         for prefix in range(12): | ||||
| @@ -124,12 +140,12 @@ class Tag: | ||||
|             if (mask, self.type & mask) in reverse_types: | ||||
|                 type = reverse_types[mask, self.type & mask] | ||||
|                 if prefix > 0: | ||||
|                     return '%s %#0*x' % ( | ||||
|                         type, prefix//4, self.type & ((1 << prefix)-1)) | ||||
|                     return '%s %#x%s' % ( | ||||
|                         type, self.type & ((1 << prefix)-1), crc_status) | ||||
|                 else: | ||||
|                     return type | ||||
|                     return '%s%s' % (type, crc_status) | ||||
|         else: | ||||
|             return '%02x' % self.type | ||||
|             return '%02x%s' % (self.type, crc_status) | ||||
|  | ||||
|     def idrepr(self): | ||||
|         return repr(self.id) if self.id != 0x3ff else '.' | ||||
| @@ -172,6 +188,8 @@ class MetadataPair: | ||||
|  | ||||
|         self.rev, = struct.unpack('<I', block[0:4]) | ||||
|         crc = binascii.crc32(block[0:4]) | ||||
|         etag = None | ||||
|         estate = None | ||||
|  | ||||
|         # parse tags | ||||
|         corrupt = False | ||||
| @@ -182,11 +200,11 @@ class MetadataPair: | ||||
|         while len(block) - off >= 4: | ||||
|             ntag, = struct.unpack('>I', block[off:off+4]) | ||||
|  | ||||
|             tag = Tag(int(tag) ^ ntag) | ||||
|             tag = Tag((int(tag) ^ ntag) & 0x7fffffff) | ||||
|             tag.off = off + 4 | ||||
|             tag.data = block[off+4:off+tag.dsize] | ||||
|             if tag.is_('crc'): | ||||
|                 crc = binascii.crc32(block[off:off+4+4], crc) | ||||
|             if tag.is_('crc') and not tag.is_('nprogcrc'): | ||||
|                 crc = binascii.crc32(block[off:off+2*4], crc) | ||||
|             else: | ||||
|                 crc = binascii.crc32(block[off:off+tag.dsize], crc) | ||||
|             tag.crc = crc | ||||
| @@ -194,16 +212,29 @@ class MetadataPair: | ||||
|  | ||||
|             self.all_.append(tag) | ||||
|  | ||||
|             if tag.is_('crc'): | ||||
|             if tag.is_('nprogcrc') and len(tag.data) == 8: | ||||
|                 etag = tag | ||||
|                 estate = struct.unpack('<II', tag.data) | ||||
|             elif tag.is_('crc'): | ||||
|                 # is valid commit? | ||||
|                 if crc != 0xffffffff: | ||||
|                     corrupt = True | ||||
|                 if not corrupt: | ||||
|                     self.log = self.all_.copy() | ||||
|                     # end of commit? | ||||
|                     if estate: | ||||
|                         esize, ecrc = estate | ||||
|                         dcrc = 0xffffffff ^ binascii.crc32(block[off:off+esize]) | ||||
|                         if ecrc == dcrc: | ||||
|                             etag.erased = True | ||||
|                             corrupt = True | ||||
|                     elif not (tag.is_('crc 0x0') or tag.is_('crc 0x1')): | ||||
|                         corrupt = True | ||||
|  | ||||
|                 # reset tag parsing | ||||
|                 crc = 0 | ||||
|                 tag = Tag(int(tag) ^ ((tag.type & 1) << 31)) | ||||
|                 etag = None | ||||
|                 estate = None | ||||
|  | ||||
|         # find active ids | ||||
|         self.ids = list(it.takewhile( | ||||
| @@ -280,7 +311,7 @@ class MetadataPair: | ||||
|         f.write('\n') | ||||
|  | ||||
|         for tag in tags: | ||||
|             f.write("%08x: %08x  %-13s %4s %4s" % ( | ||||
|             f.write("%08x: %08x  %-14s %3s %4s" % ( | ||||
|                 tag.off, tag, | ||||
|                 tag.typerepr(), tag.idrepr(), tag.sizerepr())) | ||||
|             if truncate: | ||||
|   | ||||
| @@ -106,7 +106,7 @@ def main(args): | ||||
|             struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff')))) | ||||
|     print("%-47s%s" % ("littlefs v%s.%s" % version, | ||||
|         "data (truncated, if it fits)" | ||||
|         if not any([args.no_truncate, args.tags, args.log, args.all]) else "")) | ||||
|         if not any([args.no_truncate, args.log, args.all]) else "")) | ||||
|  | ||||
|     # print gstate | ||||
|     print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) | ||||
|   | ||||
							
								
								
									
										172
									
								
								tests/test_powerloss.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								tests/test_powerloss.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| # There are already a number of tests that test general operations under | ||||
| # power-loss (see the reentrant attribute). These tests are for explicitly | ||||
| # testing specific corner cases. | ||||
|  | ||||
| [[case]] # only a revision count | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "notebook") => 0; | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     strcpy((char*)buffer, "hello"); | ||||
|     size = strlen("hello"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     char rbuffer[256]; | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // get pair/rev count | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir, "notebook") => 0; | ||||
|     lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]}; | ||||
|     uint32_t rev = dir.m.rev; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // write just the revision count | ||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, pair[1], 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|  | ||||
|     memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t)); | ||||
|  | ||||
|     cfg.erase(&cfg, pair[1]) => 0; | ||||
|     cfg.prog(&cfg, pair[1], 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|  | ||||
|     // can read? | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     // can write? | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", | ||||
|             LFS_O_WRONLY | LFS_O_APPEND) => 0; | ||||
|     strcpy((char*)buffer, "goodbye"); | ||||
|     size = strlen("goodbye"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; | ||||
|     strcpy((char*)buffer, "hello"); | ||||
|     size = strlen("hello"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     strcpy((char*)buffer, "goodbye"); | ||||
|     size = strlen("goodbye"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # partial prog, may not be byte in order! | ||||
| if = "LFS_PROG_SIZE < LFS_BLOCK_SIZE" | ||||
| define.BYTE_OFF = ["0", "LFS_PROG_SIZE-1", "LFS_PROG_SIZE/2"] | ||||
| define.BYTE_VALUE = [0x33, 0xcc] | ||||
| in = "lfs.c" | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "notebook") => 0; | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     strcpy((char*)buffer, "hello"); | ||||
|     size = strlen("hello"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     char rbuffer[256]; | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // imitate a partial prog, value should not matter, if littlefs | ||||
|     // doesn't notice the partial prog testbd will assert | ||||
|  | ||||
|     // get offset to next prog | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir, "notebook") => 0; | ||||
|     lfs_block_t block = dir.m.pair[0]; | ||||
|     lfs_off_t off = dir.m.off; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // tweak byte | ||||
|     uint8_t bbuffer[LFS_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|  | ||||
|     bbuffer[off + BYTE_OFF] = BYTE_VALUE; | ||||
|  | ||||
|     cfg.erase(&cfg, block) => 0; | ||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|  | ||||
|     // can read? | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     // can write? | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", | ||||
|             LFS_O_WRONLY | LFS_O_APPEND) => 0; | ||||
|     strcpy((char*)buffer, "goodbye"); | ||||
|     size = strlen("goodbye"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; | ||||
|     strcpy((char*)buffer, "hello"); | ||||
|     size = strlen("hello"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     strcpy((char*)buffer, "goodbye"); | ||||
|     size = strlen("goodbye"); | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
		Reference in New Issue
	
	Block a user