mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	WIP Added limits on name/attrs/inline sizes
This commit is contained in:
		
							
								
								
									
										150
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -365,6 +365,9 @@ static void lfs_superblock_fromle32(struct lfs_disk_superblock *d) { | ||||
|     d->block_size  = lfs_fromle32(d->block_size); | ||||
|     d->block_count = lfs_fromle32(d->block_count); | ||||
|     d->version     = lfs_fromle32(d->version); | ||||
|     d->inline_size = lfs_fromle32(d->inline_size); | ||||
|     d->attrs_size  = lfs_fromle32(d->attrs_size); | ||||
|     d->name_size   = lfs_fromle32(d->name_size); | ||||
| } | ||||
|  | ||||
| static void lfs_superblock_tole32(struct lfs_disk_superblock *d) { | ||||
| @@ -373,6 +376,9 @@ static void lfs_superblock_tole32(struct lfs_disk_superblock *d) { | ||||
|     d->block_size  = lfs_tole32(d->block_size); | ||||
|     d->block_count = lfs_tole32(d->block_count); | ||||
|     d->version     = lfs_tole32(d->version); | ||||
|     d->inline_size = lfs_tole32(d->inline_size); | ||||
|     d->attrs_size  = lfs_tole32(d->attrs_size); | ||||
|     d->name_size   = lfs_tole32(d->name_size); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -1018,6 +1024,12 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|         return err ? err : LFS_ERR_EXIST; | ||||
|     } | ||||
|  | ||||
|     // check that name fits | ||||
|     lfs_size_t nlen = strlen(path); | ||||
|     if (nlen > lfs->name_size) { | ||||
|         return LFS_ERR_NAMETOOLONG; | ||||
|     } | ||||
|  | ||||
|     // build up new directory | ||||
|     lfs_alloc_ack(lfs); | ||||
|  | ||||
| @@ -1037,7 +1049,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|     entry.d.type = LFS_STRUCT_DIR | LFS_TYPE_DIR; | ||||
|     entry.d.elen = sizeof(entry.d) - 4; | ||||
|     entry.d.alen = 0; | ||||
|     entry.d.nlen = strlen(path); | ||||
|     entry.d.nlen = nlen; | ||||
|     entry.d.u.dir[0] = dir.pair[0]; | ||||
|     entry.d.u.dir[1] = dir.pair[1]; | ||||
|     entry.size = 0; | ||||
| @@ -1046,7 +1058,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|     cwd.d.tail[1] = dir.pair[1]; | ||||
|     err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ | ||||
|             {LFS_FROM_MEM, 0, &entry.d, sizeof(entry.d)}, | ||||
|             {LFS_FROM_MEM, 0, path, entry.d.nlen}}, 2); | ||||
|             {LFS_FROM_MEM, 0, path, nlen}}, 2); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -1427,16 +1439,22 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|             return LFS_ERR_NOENT; | ||||
|         } | ||||
|  | ||||
|         // check that name fits | ||||
|         lfs_size_t nlen = strlen(path); | ||||
|         if (nlen > lfs->name_size) { | ||||
|             return LFS_ERR_NAMETOOLONG; | ||||
|         } | ||||
|  | ||||
|         // create entry to remember name | ||||
|         entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG; | ||||
|         entry.d.elen = 0; | ||||
|         entry.d.alen = 0; | ||||
|         entry.d.nlen = strlen(path); | ||||
|         entry.d.nlen = nlen; | ||||
|         entry.size = 0; | ||||
|  | ||||
|         err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ | ||||
|                 {LFS_FROM_MEM, 0, &entry.d, 4}, | ||||
|                 {LFS_FROM_MEM, 0, path, entry.d.nlen}}, 2); | ||||
|                 {LFS_FROM_MEM, 0, path, nlen}}, 2); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -1571,10 +1589,6 @@ relocate:; | ||||
|  | ||||
| static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||
|     if (file->flags & LFS_F_READING) { | ||||
|         if (!(file->flags & LFS_F_INLINE)) { | ||||
|             // just drop read cache | ||||
|             file->cache.block = 0xffffffff; | ||||
|         } | ||||
|         file->flags &= ~LFS_F_READING; | ||||
|     } | ||||
|  | ||||
| @@ -1807,9 +1821,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
|     // TODO need to move out if no longer fits in block also | ||||
|     // TODO store INLINE_MAX in superblock? | ||||
|     // TODO what if inline files is > block size (ie 128) | ||||
|     if ((file->flags & LFS_F_INLINE) && ( | ||||
|          (file->pos + nsize >= LFS_INLINE_MAX) || | ||||
|          (file->pos + nsize >= lfs->cfg->read_size))) { | ||||
|     if ((file->flags & LFS_F_INLINE) && | ||||
|             file->pos + nsize >= lfs->inline_size) { | ||||
|         file->block = 0xfffffffe; | ||||
|         file->off = file->pos; | ||||
|  | ||||
| @@ -2137,6 +2150,12 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     bool prevexists = (err != LFS_ERR_NOENT); | ||||
|     bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0); | ||||
|  | ||||
|     // check that name fits | ||||
|     lfs_size_t nlen = strlen(newpath); | ||||
|     if (nlen > lfs->name_size) { | ||||
|         return LFS_ERR_NAMETOOLONG; | ||||
|     } | ||||
|  | ||||
|     // must have same type | ||||
|     if (prevexists && preventry.d.type != oldentry.d.type) { | ||||
|         return LFS_ERR_ISDIR; | ||||
| @@ -2174,7 +2193,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     lfs_entry_t newentry = preventry; | ||||
|     newentry.d = oldentry.d; | ||||
|     newentry.d.type &= ~LFS_STRUCT_MOVED; | ||||
|     newentry.d.nlen = strlen(newpath); | ||||
|     newentry.d.nlen = nlen; | ||||
|     if (!prevexists) { | ||||
|         newentry.size = 0; | ||||
|     } | ||||
| @@ -2185,8 +2204,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|                 oldcwd.pair[0], oldentry.off, (struct lfs_region[]){ | ||||
|                     {LFS_FROM_MEM, 0, &newentry.d, 4}, | ||||
|                     {LFS_FROM_DROP, 0, NULL, -4}, | ||||
|                     {LFS_FROM_MEM, newsize - newentry.d.nlen, | ||||
|                         newpath, newentry.d.nlen}}, 3}, | ||||
|                     {LFS_FROM_MEM, newsize - nlen, newpath, nlen}}, 3}, | ||||
|                 newsize}, | ||||
|             {LFS_FROM_DROP, 0, NULL, -preventry.size}}, prevexists ? 2 : 1); | ||||
|     if (err) { | ||||
| @@ -2272,6 +2290,26 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) | ||||
|             <= lfs->cfg->block_size); | ||||
|  | ||||
|     // check that the size limits are sane | ||||
|     LFS_ASSERT(lfs->cfg->inline_size <= LFS_INLINE_MAX); | ||||
|     LFS_ASSERT(lfs->cfg->inline_size <= lfs->cfg->read_size); | ||||
|     lfs->inline_size = lfs->cfg->inline_size; | ||||
|     if (!lfs->inline_size) { | ||||
|         lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size); | ||||
|     } | ||||
|  | ||||
|     LFS_ASSERT(lfs->cfg->attrs_size <= LFS_ATTRS_MAX); | ||||
|     lfs->attrs_size = lfs->cfg->attrs_size; | ||||
|     if (!lfs->attrs_size) { | ||||
|         lfs->attrs_size = LFS_ATTRS_MAX; | ||||
|     } | ||||
|  | ||||
|     LFS_ASSERT(lfs->cfg->name_size <= LFS_NAME_MAX); | ||||
|     lfs->name_size = lfs->cfg->name_size; | ||||
|     if (!lfs->name_size) { | ||||
|         lfs->name_size = LFS_NAME_MAX; | ||||
|     } | ||||
|  | ||||
|     // setup default state | ||||
|     lfs->root[0] = 0xffffffff; | ||||
|     lfs->root[1] = 0xffffffff; | ||||
| @@ -2336,13 +2374,16 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     superdir.d.tail[0] = lfs->root[0]; | ||||
|     superdir.d.tail[1] = lfs->root[1]; | ||||
|  | ||||
|     // write one superblocks | ||||
|     // write one superblock | ||||
|     lfs_superblock_t superblock; | ||||
|     superblock.d.version = LFS_DISK_VERSION, | ||||
|     superblock.d.root[0] = lfs->root[0]; | ||||
|     superblock.d.root[1] = lfs->root[1]; | ||||
|     superblock.d.block_size  = lfs->cfg->block_size; | ||||
|     superblock.d.block_count = lfs->cfg->block_count; | ||||
|     superblock.d.inline_size = lfs->inline_size; | ||||
|     superblock.d.attrs_size  = lfs->attrs_size; | ||||
|     superblock.d.name_size   = lfs->name_size; | ||||
|  | ||||
|     lfs_entry_t superentry; | ||||
|     superentry.d.type = LFS_STRUCT_DIR | LFS_TYPE_SUPERBLOCK; | ||||
| @@ -2385,33 +2426,41 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|  | ||||
|     // load superblock | ||||
|     lfs_dir_t dir; | ||||
|     lfs_entry_t entry; | ||||
|     lfs_superblock_t superblock; | ||||
|     char magic[8]; | ||||
|  | ||||
|     err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||
|     if (err && err != LFS_ERR_CORRUPT) { | ||||
|     if (err) { | ||||
|         if (err == LFS_ERR_CORRUPT) { | ||||
|             LFS_ERROR("Invalid superblock at %d %d", 0, 1); | ||||
|         } | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (!err) { | ||||
|         err = lfs_dir_get(lfs, &dir, | ||||
|                 sizeof(dir.d)+4, &superblock.d, sizeof(superblock.d)); | ||||
|         lfs_superblock_fromle32(&superblock.d); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         err = lfs_dir_get(lfs, &dir, | ||||
|                 sizeof(dir.d)+4 + sizeof(superblock.d), magic, sizeof(magic)); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         lfs->root[0] = superblock.d.root[0]; | ||||
|         lfs->root[1] = superblock.d.root[1]; | ||||
|     err = lfs_dir_get(lfs, &dir, sizeof(dir.d), &entry.d, sizeof(entry.d)); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (err || memcmp(magic, "littlefs", 8) != 0) { | ||||
|         LFS_ERROR("Invalid superblock at %d %d", dir.pair[0], dir.pair[1]); | ||||
|     memset(&superblock.d, 0, sizeof(superblock.d)); | ||||
|     err = lfs_dir_get(lfs, &dir, | ||||
|             sizeof(dir.d)+4, &superblock.d, | ||||
|             lfs_min(sizeof(superblock.d), entry.d.elen)); | ||||
|     lfs_superblock_fromle32(&superblock.d); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     err = lfs_dir_get(lfs, &dir, | ||||
|             sizeof(dir.d)+4+entry.d.elen+entry.d.alen, magic, | ||||
|             lfs_min(sizeof(magic), entry.d.nlen)); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (memcmp(magic, "littlefs", 8) != 0) { | ||||
|         LFS_ERROR("Invalid superblock at %d %d", 0, 1); | ||||
|         return LFS_ERR_CORRUPT; | ||||
|     } | ||||
|  | ||||
| @@ -2423,6 +2472,39 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|         return LFS_ERR_INVAL; | ||||
|     } | ||||
|  | ||||
|     if (superblock.d.inline_size) { | ||||
|         if (superblock.d.inline_size > lfs->inline_size) { | ||||
|             LFS_ERROR("Unsupported inline size (%d > %d)", | ||||
|                     superblock.d.inline_size, lfs->inline_size); | ||||
|             return LFS_ERR_INVAL; | ||||
|         } | ||||
|  | ||||
|         lfs->inline_size = superblock.d.inline_size; | ||||
|     } | ||||
|  | ||||
|     if (superblock.d.attrs_size) { | ||||
|         if (superblock.d.attrs_size > lfs->attrs_size) { | ||||
|             LFS_ERROR("Unsupported attrs size (%d > %d)", | ||||
|                     superblock.d.attrs_size, lfs->attrs_size); | ||||
|             return LFS_ERR_INVAL; | ||||
|         } | ||||
|  | ||||
|         lfs->attrs_size = superblock.d.attrs_size; | ||||
|     } | ||||
|  | ||||
|     if (superblock.d.name_size) { | ||||
|         if (superblock.d.name_size > lfs->name_size) { | ||||
|             LFS_ERROR("Unsupported name size (%d > %d)", | ||||
|                     superblock.d.name_size, lfs->name_size); | ||||
|             return LFS_ERR_INVAL; | ||||
|         } | ||||
|  | ||||
|         lfs->name_size = superblock.d.name_size; | ||||
|     } | ||||
|  | ||||
|     lfs->root[0] = superblock.d.root[0]; | ||||
|     lfs->root[1] = superblock.d.root[1]; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										67
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -50,30 +50,37 @@ typedef int32_t  lfs_soff_t; | ||||
|  | ||||
| typedef uint32_t lfs_block_t; | ||||
|  | ||||
| // Maximum inline file size in bytes | ||||
| #ifndef LFS_INLINE_MAX | ||||
| #define LFS_INLINE_MAX 255 | ||||
| #endif | ||||
|  | ||||
| // Maximum size of all attributes per file in bytes | ||||
| #ifndef LFS_ATTRS_MAX | ||||
| #define LFS_ATTRS_MAX 255 | ||||
| #endif | ||||
|  | ||||
| // Max name size in bytes | ||||
| #ifndef LFS_NAME_MAX | ||||
| #define LFS_NAME_MAX 255 | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_INLINE_MAX | ||||
| #define LFS_INLINE_MAX 255 | ||||
| #endif | ||||
|  | ||||
| // Possible error codes, these are negative to allow | ||||
| // valid positive return values | ||||
| enum lfs_error { | ||||
|     LFS_ERR_OK       = 0,    // No error | ||||
|     LFS_ERR_IO       = -5,   // Error during device operation | ||||
|     LFS_ERR_CORRUPT  = -52,  // Corrupted | ||||
|     LFS_ERR_NOENT    = -2,   // No directory entry | ||||
|     LFS_ERR_EXIST    = -17,  // Entry already exists | ||||
|     LFS_ERR_NOTDIR   = -20,  // Entry is not a dir | ||||
|     LFS_ERR_ISDIR    = -21,  // Entry is a dir | ||||
|     LFS_ERR_NOTEMPTY = -39,  // Dir is not empty | ||||
|     LFS_ERR_BADF     = -9,   // Bad file number | ||||
|     LFS_ERR_INVAL    = -22,  // Invalid parameter | ||||
|     LFS_ERR_NOSPC    = -28,  // No space left on device | ||||
|     LFS_ERR_NOMEM    = -12,  // No more memory available | ||||
|     LFS_ERR_OK          = 0,    // No error | ||||
|     LFS_ERR_IO          = -5,   // Error during device operation | ||||
|     LFS_ERR_CORRUPT     = -52,  // Corrupted | ||||
|     LFS_ERR_NOENT       = -2,   // No directory entry | ||||
|     LFS_ERR_EXIST       = -17,  // Entry already exists | ||||
|     LFS_ERR_NOTDIR      = -20,  // Entry is not a dir | ||||
|     LFS_ERR_ISDIR       = -21,  // Entry is a dir | ||||
|     LFS_ERR_NOTEMPTY    = -39,  // Dir is not empty | ||||
|     LFS_ERR_BADF        = -9,   // Bad file number | ||||
|     LFS_ERR_INVAL       = -22,  // Invalid parameter | ||||
|     LFS_ERR_NOSPC       = -28,  // No space left on device | ||||
|     LFS_ERR_NOMEM       = -12,  // No more memory available | ||||
|     LFS_ERR_NAMETOOLONG = -36,  // File name too long | ||||
| }; | ||||
|  | ||||
| // File types | ||||
| @@ -102,10 +109,10 @@ enum lfs_open_flags { | ||||
|     LFS_O_APPEND = 0x0800,    // Move to end of file on every write | ||||
|  | ||||
|     // internally used flags | ||||
|     LFS_F_DIRTY   = 0x10000,  // File does not match storage | ||||
|     LFS_F_WRITING = 0x20000,  // File has been written since last flush | ||||
|     LFS_F_READING = 0x40000,  // File has been read since last flush | ||||
|     LFS_F_ERRED   = 0x80000,  // An error occured during write | ||||
|     LFS_F_DIRTY   = 0x010000, // File does not match storage | ||||
|     LFS_F_WRITING = 0x020000, // File has been written since last flush | ||||
|     LFS_F_READING = 0x040000, // File has been read since last flush | ||||
|     LFS_F_ERRED   = 0x080000, // An error occured during write | ||||
|     LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry | ||||
| }; | ||||
|  | ||||
| @@ -183,6 +190,13 @@ struct lfs_config { | ||||
|     // Optional, statically allocated buffer for files. Must be program sized. | ||||
|     // If enabled, only one file may be opened at a time. | ||||
|     void *file_buffer; | ||||
|  | ||||
|     // Optional, | ||||
|     lfs_size_t inline_size; | ||||
|     // Optional, | ||||
|     lfs_size_t attrs_size; | ||||
|     // Optional, | ||||
|     lfs_size_t name_size; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @@ -258,9 +272,14 @@ typedef struct lfs_dir { | ||||
| typedef struct lfs_superblock { | ||||
|     struct lfs_disk_superblock { | ||||
|         lfs_block_t root[2]; | ||||
|         uint32_t block_size; | ||||
|         uint32_t block_count; | ||||
|  | ||||
|         lfs_size_t block_size; | ||||
|         lfs_size_t block_count; | ||||
|         uint32_t version; | ||||
|  | ||||
|         lfs_size_t inline_size; | ||||
|         lfs_size_t attrs_size; | ||||
|         lfs_size_t name_size; | ||||
|     } d; | ||||
| } lfs_superblock_t; | ||||
|  | ||||
| @@ -285,6 +304,10 @@ typedef struct lfs { | ||||
|  | ||||
|     lfs_free_t free; | ||||
|     bool deorphaned; | ||||
|  | ||||
|     lfs_size_t inline_size; | ||||
|     lfs_size_t attrs_size; | ||||
|     lfs_size_t name_size; | ||||
| } lfs_t; | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user