From bba71b23f4ed5eee128800c58fdd0c6ccee1605d Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 1 Apr 2018 15:36:29 -0500 Subject: [PATCH] WIP Added limits on name/attrs/inline sizes --- lfs.c | 150 +++++++++++++++++++++++++++++++++++++++++++++------------- lfs.h | 67 +++++++++++++++++--------- 2 files changed, 161 insertions(+), 56 deletions(-) diff --git a/lfs.c b/lfs.c index 8d3017c..ad3ad04 100644 --- a/lfs.c +++ b/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; } diff --git a/lfs.h b/lfs.h index 6acf5e7..9a7b8c3 100644 --- a/lfs.h +++ b/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;