mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Added deletion to custom attributes
This follows from enabling tag deletion, however does require some consideration with the APIs. Now we can remove custom attributes, as well as determine if an attribute exists or not.
This commit is contained in:
		
							
								
								
									
										39
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -401,7 +401,7 @@ static inline lfs_size_t lfs_tag_size(uint32_t tag) { | |||||||
| } | } | ||||||
|  |  | ||||||
| static inline lfs_size_t lfs_tag_dsize(uint32_t tag) { | static inline lfs_size_t lfs_tag_dsize(uint32_t tag) { | ||||||
|     return sizeof(tag) + lfs_tag_size(tag) + lfs_tag_isdelete(tag); |     return sizeof(tag) + lfs_tag_size(tag + lfs_tag_isdelete(tag)); | ||||||
| } | } | ||||||
|  |  | ||||||
| // operations on set of globals | // operations on set of globals | ||||||
| @@ -472,7 +472,7 @@ struct lfs_diskoff { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| static int32_t lfs_commit_get(lfs_t *lfs, | static int32_t lfs_commit_get(lfs_t *lfs, | ||||||
|         lfs_block_t block, lfs_off_t off, uint32_t tag, bool stopatcommit, |         lfs_block_t block, lfs_off_t off, uint32_t tag, bool compacting, | ||||||
|         uint32_t getmask, uint32_t gettag, int32_t getdiff, void *buffer) { |         uint32_t getmask, uint32_t gettag, int32_t getdiff, void *buffer) { | ||||||
|     gettag += getdiff; |     gettag += getdiff; | ||||||
|  |  | ||||||
| @@ -480,7 +480,7 @@ static int32_t lfs_commit_get(lfs_t *lfs, | |||||||
|     while (off >= sizeof(uint32_t) + lfs_tag_dsize(tag)) { |     while (off >= sizeof(uint32_t) + lfs_tag_dsize(tag)) { | ||||||
|         off -= lfs_tag_dsize(tag); |         off -= lfs_tag_dsize(tag); | ||||||
|  |  | ||||||
|         if (lfs_tag_subtype(tag) == LFS_TYPE_CRC && stopatcommit) { |         if (lfs_tag_subtype(tag) == LFS_TYPE_CRC && compacting) { | ||||||
|             break; |             break; | ||||||
|         } else if (lfs_tag_subtype(tag) == LFS_TYPE_DELETE) { |         } else if (lfs_tag_subtype(tag) == LFS_TYPE_DELETE) { | ||||||
|             // something was deleted, need to move around it |             // something was deleted, need to move around it | ||||||
| @@ -489,8 +489,11 @@ static int32_t lfs_commit_get(lfs_t *lfs, | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!lfs_tag_isdelete(tag) && |         if ((tag & getmask) == ((gettag - getdiff) & getmask)) { | ||||||
|                 (tag & getmask) == ((gettag - getdiff) & getmask)) { |             if (lfs_tag_isdelete(tag) && !compacting) { | ||||||
|  |                 return LFS_ERR_NOENT; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             if (buffer) { |             if (buffer) { | ||||||
|                 lfs_size_t diff = lfs_min( |                 lfs_size_t diff = lfs_min( | ||||||
|                         lfs_tag_size(gettag), lfs_tag_size(tag)); |                         lfs_tag_size(gettag), lfs_tag_size(tag)); | ||||||
| @@ -2912,19 +2915,18 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | |||||||
|     res = lfs_dir_get(lfs, &cwd, 0x7ffff000, |     res = lfs_dir_get(lfs, &cwd, 0x7ffff000, | ||||||
|             LFS_MKTAG(0x100 | type, id, lfs_min(size, lfs->attr_max)), |             LFS_MKTAG(0x100 | type, id, lfs_min(size, lfs->attr_max)), | ||||||
|             buffer); |             buffer); | ||||||
|     if (res < 0 && res != LFS_ERR_NOENT) { |     if (res < 0) { | ||||||
|  |         if (res == LFS_ERR_NOENT) { | ||||||
|  |             return LFS_ERR_NOATTR; | ||||||
|  |         } | ||||||
|         return res; |         return res; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return (res == LFS_ERR_NOENT) ? 0 : lfs_tag_size(res); |     return lfs_tag_size(res); | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_setattr(lfs_t *lfs, const char *path, | static int lfs_commitattr(lfs_t *lfs, const char *path, | ||||||
|         uint8_t type, const void *buffer, lfs_size_t size) { |         uint8_t type, const void *buffer, lfs_size_t size) { | ||||||
|     if (size > lfs->attr_max) { |  | ||||||
|         return LFS_ERR_NOSPC; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_mdir_t cwd; |     lfs_mdir_t cwd; | ||||||
|     int32_t res = lfs_dir_lookup(lfs, &cwd, &path); |     int32_t res = lfs_dir_lookup(lfs, &cwd, &path); | ||||||
|     if (res < 0) { |     if (res < 0) { | ||||||
| @@ -2946,6 +2948,19 @@ int lfs_setattr(lfs_t *lfs, const char *path, | |||||||
|             NULL)); |             NULL)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int lfs_setattr(lfs_t *lfs, const char *path, | ||||||
|  |         uint8_t type, const void *buffer, lfs_size_t size) { | ||||||
|  |     if (size > lfs->attr_max) { | ||||||
|  |         return LFS_ERR_NOSPC; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return lfs_commitattr(lfs, path, type, buffer, size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { | ||||||
|  |     return lfs_commitattr(lfs, path, type, NULL, 0xfff); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Filesystem operations /// | /// Filesystem operations /// | ||||||
| static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -82,6 +82,7 @@ enum lfs_error { | |||||||
|     LFS_ERR_INVAL       = -22,  // Invalid parameter |     LFS_ERR_INVAL       = -22,  // Invalid parameter | ||||||
|     LFS_ERR_NOSPC       = -28,  // No space left on device |     LFS_ERR_NOSPC       = -28,  // No space left on device | ||||||
|     LFS_ERR_NOMEM       = -12,  // No more memory available |     LFS_ERR_NOMEM       = -12,  // No more memory available | ||||||
|  |     LFS_ERR_NOATTR      = -61,  // No data/attr available | ||||||
|     LFS_ERR_NAMETOOLONG = -36,  // File name too long |     LFS_ERR_NAMETOOLONG = -36,  // File name too long | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -456,7 +457,8 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); | |||||||
| // Custom attributes are uniquely identified by an 8-bit type and limited | // Custom attributes are uniquely identified by an 8-bit type and limited | ||||||
| // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than | // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than | ||||||
| // the buffer, it will be padded with zeros. If the stored attribute is larger, | // the buffer, it will be padded with zeros. If the stored attribute is larger, | ||||||
| // then it will be silently truncated. | // then it will be silently truncated. If no attribute is found, the error | ||||||
|  | // LFS_ERR_NOATTR is returned and the buffer is filled with zeros. | ||||||
| // | // | ||||||
| // Returns the size of the attribute, or a negative error code on failure. | // Returns the size of the attribute, or a negative error code on failure. | ||||||
| // Note, the returned size is the size of the attribute on disk, irrespective | // Note, the returned size is the size of the attribute on disk, irrespective | ||||||
| @@ -469,13 +471,19 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | |||||||
| // | // | ||||||
| // Custom attributes are uniquely identified by an 8-bit type and limited | // Custom attributes are uniquely identified by an 8-bit type and limited | ||||||
| // to LFS_ATTR_MAX bytes. If an attribute is not found, it will be | // to LFS_ATTR_MAX bytes. If an attribute is not found, it will be | ||||||
| // implicitly created, and setting the size of an attribute to zero deletes | // implicitly created. | ||||||
| // the attribute. |  | ||||||
| // | // | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_setattr(lfs_t *lfs, const char *path, | int lfs_setattr(lfs_t *lfs, const char *path, | ||||||
|         uint8_t type, const void *buffer, lfs_size_t size); |         uint8_t type, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
|  | // 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); | ||||||
|  |  | ||||||
|  |  | ||||||
| /// File operations /// | /// File operations /// | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,10 +19,11 @@ def corrupt(block): | |||||||
|                 break |                 break | ||||||
|  |  | ||||||
|             tag ^= ntag |             tag ^= ntag | ||||||
|             file.seek(tag & 0xfff, os.SEEK_CUR) |             size = (tag & 0xfff) if (tag & 0xfff) != 0xfff else 0 | ||||||
|  |             file.seek(size, os.SEEK_CUR) | ||||||
|  |  | ||||||
|         # lob off last 3 bytes |         # lob off last 3 bytes | ||||||
|         file.seek(-((tag & 0xfff) + 3), os.SEEK_CUR) |         file.seek(-(size + 3), os.SEEK_CUR) | ||||||
|         file.truncate() |         file.truncate() | ||||||
|  |  | ||||||
| def main(args): | def main(args): | ||||||
|   | |||||||
| @@ -81,20 +81,21 @@ def main(*blocks): | |||||||
|         size = (tag & 0x00000fff) >> 0 |         size = (tag & 0x00000fff) >> 0 | ||||||
|         iscrc = (type & 0x1f0) == 0x0f0 |         iscrc = (type & 0x1f0) == 0x0f0 | ||||||
|  |  | ||||||
|         data = file.read(size) |         data = file.read(size if size != 0xfff else 0) | ||||||
|         if iscrc: |         if iscrc: | ||||||
|             crc = binascii.crc32(data[:4], crc) |             crc = binascii.crc32(data[:4], crc) | ||||||
|         else: |         else: | ||||||
|             crc = binascii.crc32(data, crc) |             crc = binascii.crc32(data, crc) | ||||||
|  |  | ||||||
|         print '%04x: %08x  %-14s  %3s  %3d  %-23s  %-8s' % ( |         print '%04x: %08x  %-14s  %3s  %3s  %-23s  %-8s' % ( | ||||||
|             off, tag, |             off, tag, | ||||||
|             typeof(type) + (' bad!' if iscrc and ~crc else ''), |             typeof(type) + (' bad!' if iscrc and ~crc else ''), | ||||||
|             id if id != 0x3ff else '.', size, |             id if id != 0x3ff else '.', | ||||||
|  |             size if size != 0xfff else 'x', | ||||||
|             ' '.join('%02x' % ord(c) for c in data[:8]), |             ' '.join('%02x' % ord(c) for c in data[:8]), | ||||||
|             ''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8])) |             ''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8])) | ||||||
|  |  | ||||||
|         off += tag & 0xfff |         off += size if size != 0xfff else 0 | ||||||
|         if iscrc: |         if iscrc: | ||||||
|             crc = 0 |             crc = 0 | ||||||
|             tag ^= (type & 1) << 31 |             tag ^= (type & 1) << 31 | ||||||
|   | |||||||
| @@ -37,6 +37,14 @@ tests/test.py << TEST | |||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |     memcmp(buffer+10, "ccccc",        5) => 0; | ||||||
|  |  | ||||||
|  |     lfs_removeattr(&lfs, "hello", 'B') => 0; | ||||||
|  |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|  |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => LFS_ERR_NOATTR; | ||||||
|  |     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||||
|  |     memcmp(buffer,    "aaaa",         4) => 0; | ||||||
|  |     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||||
|  |     memcmp(buffer+10, "ccccc",        5) => 0; | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; |     lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||||
| @@ -98,6 +106,14 @@ tests/test.py << TEST | |||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |     memcmp(buffer+10, "ccccc",        5) => 0; | ||||||
|  |  | ||||||
|  |     lfs_removeattr(&lfs, "/", 'B') => 0; | ||||||
|  |     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||||
|  |     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => LFS_ERR_NOATTR; | ||||||
|  |     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||||
|  |     memcmp(buffer,    "aaaa",         4) => 0; | ||||||
|  |     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||||
|  |     memcmp(buffer+10, "ccccc",        5) => 0; | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; |     lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; |     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; | ||||||
| @@ -241,7 +257,7 @@ tests/test.py << TEST | |||||||
|  |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; |     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; |     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 0; |     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; | ||||||
|     memcmp(buffer,    "fffffffff",          9) => 0; |     memcmp(buffer,    "fffffffff",          9) => 0; | ||||||
|     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; |     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; | ||||||
|     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; |     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user