WIP Added limits on name/attrs/inline sizes

This commit is contained in:
Christopher Haster
2018-04-01 15:36:29 -05:00
parent e4a35b78e7
commit bba71b23f4
2 changed files with 161 additions and 56 deletions

132
lfs.c
View File

@@ -365,6 +365,9 @@ static void lfs_superblock_fromle32(struct lfs_disk_superblock *d) {
d->block_size = lfs_fromle32(d->block_size); d->block_size = lfs_fromle32(d->block_size);
d->block_count = lfs_fromle32(d->block_count); d->block_count = lfs_fromle32(d->block_count);
d->version = lfs_fromle32(d->version); 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) { 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_size = lfs_tole32(d->block_size);
d->block_count = lfs_tole32(d->block_count); d->block_count = lfs_tole32(d->block_count);
d->version = lfs_tole32(d->version); 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; 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 // build up new directory
lfs_alloc_ack(lfs); 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.type = LFS_STRUCT_DIR | LFS_TYPE_DIR;
entry.d.elen = sizeof(entry.d) - 4; entry.d.elen = sizeof(entry.d) - 4;
entry.d.alen = 0; 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[0] = dir.pair[0];
entry.d.u.dir[1] = dir.pair[1]; entry.d.u.dir[1] = dir.pair[1];
entry.size = 0; entry.size = 0;
@@ -1046,7 +1058,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
cwd.d.tail[1] = dir.pair[1]; cwd.d.tail[1] = dir.pair[1];
err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
{LFS_FROM_MEM, 0, &entry.d, sizeof(entry.d)}, {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) { if (err) {
return err; return err;
} }
@@ -1427,16 +1439,22 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
return LFS_ERR_NOENT; 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 // create entry to remember name
entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG; entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG;
entry.d.elen = 0; entry.d.elen = 0;
entry.d.alen = 0; entry.d.alen = 0;
entry.d.nlen = strlen(path); entry.d.nlen = nlen;
entry.size = 0; entry.size = 0;
err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
{LFS_FROM_MEM, 0, &entry.d, 4}, {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) { if (err) {
return err; return err;
} }
@@ -1571,10 +1589,6 @@ relocate:;
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
if (file->flags & LFS_F_READING) { 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; 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 need to move out if no longer fits in block also
// TODO store INLINE_MAX in superblock? // TODO store INLINE_MAX in superblock?
// TODO what if inline files is > block size (ie 128) // TODO what if inline files is > block size (ie 128)
if ((file->flags & LFS_F_INLINE) && ( if ((file->flags & LFS_F_INLINE) &&
(file->pos + nsize >= LFS_INLINE_MAX) || file->pos + nsize >= lfs->inline_size) {
(file->pos + nsize >= lfs->cfg->read_size))) {
file->block = 0xfffffffe; file->block = 0xfffffffe;
file->off = file->pos; 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 prevexists = (err != LFS_ERR_NOENT);
bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0); 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 // must have same type
if (prevexists && preventry.d.type != oldentry.d.type) { if (prevexists && preventry.d.type != oldentry.d.type) {
return LFS_ERR_ISDIR; 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; lfs_entry_t newentry = preventry;
newentry.d = oldentry.d; newentry.d = oldentry.d;
newentry.d.type &= ~LFS_STRUCT_MOVED; newentry.d.type &= ~LFS_STRUCT_MOVED;
newentry.d.nlen = strlen(newpath); newentry.d.nlen = nlen;
if (!prevexists) { if (!prevexists) {
newentry.size = 0; 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[]){ oldcwd.pair[0], oldentry.off, (struct lfs_region[]){
{LFS_FROM_MEM, 0, &newentry.d, 4}, {LFS_FROM_MEM, 0, &newentry.d, 4},
{LFS_FROM_DROP, 0, NULL, -4}, {LFS_FROM_DROP, 0, NULL, -4},
{LFS_FROM_MEM, newsize - newentry.d.nlen, {LFS_FROM_MEM, newsize - nlen, newpath, nlen}}, 3},
newpath, newentry.d.nlen}}, 3},
newsize}, newsize},
{LFS_FROM_DROP, 0, NULL, -preventry.size}}, prevexists ? 2 : 1); {LFS_FROM_DROP, 0, NULL, -preventry.size}}, prevexists ? 2 : 1);
if (err) { 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_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4))
<= lfs->cfg->block_size); <= 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 // setup default state
lfs->root[0] = 0xffffffff; lfs->root[0] = 0xffffffff;
lfs->root[1] = 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[0] = lfs->root[0];
superdir.d.tail[1] = lfs->root[1]; superdir.d.tail[1] = lfs->root[1];
// write one superblocks // write one superblock
lfs_superblock_t superblock; lfs_superblock_t superblock;
superblock.d.version = LFS_DISK_VERSION, superblock.d.version = LFS_DISK_VERSION,
superblock.d.root[0] = lfs->root[0]; superblock.d.root[0] = lfs->root[0];
superblock.d.root[1] = lfs->root[1]; superblock.d.root[1] = lfs->root[1];
superblock.d.block_size = lfs->cfg->block_size; superblock.d.block_size = lfs->cfg->block_size;
superblock.d.block_count = lfs->cfg->block_count; 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; lfs_entry_t superentry;
superentry.d.type = LFS_STRUCT_DIR | LFS_TYPE_SUPERBLOCK; 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 // load superblock
lfs_dir_t dir; lfs_dir_t dir;
lfs_entry_t entry;
lfs_superblock_t superblock; lfs_superblock_t superblock;
char magic[8]; char magic[8];
err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); 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; return err;
} }
if (!err) { err = lfs_dir_get(lfs, &dir, sizeof(dir.d), &entry.d, sizeof(entry.d));
if (err) {
return err;
}
memset(&superblock.d, 0, sizeof(superblock.d));
err = lfs_dir_get(lfs, &dir, err = lfs_dir_get(lfs, &dir,
sizeof(dir.d)+4, &superblock.d, sizeof(superblock.d)); sizeof(dir.d)+4, &superblock.d,
lfs_min(sizeof(superblock.d), entry.d.elen));
lfs_superblock_fromle32(&superblock.d); lfs_superblock_fromle32(&superblock.d);
if (err) { if (err) {
return err; return err;
} }
err = lfs_dir_get(lfs, &dir, err = lfs_dir_get(lfs, &dir,
sizeof(dir.d)+4 + sizeof(superblock.d), magic, sizeof(magic)); sizeof(dir.d)+4+entry.d.elen+entry.d.alen, magic,
lfs_min(sizeof(magic), entry.d.nlen));
if (err) { if (err) {
return err; return err;
} }
lfs->root[0] = superblock.d.root[0]; if (memcmp(magic, "littlefs", 8) != 0) {
lfs->root[1] = superblock.d.root[1]; LFS_ERROR("Invalid superblock at %d %d", 0, 1);
}
if (err || memcmp(magic, "littlefs", 8) != 0) {
LFS_ERROR("Invalid superblock at %d %d", dir.pair[0], dir.pair[1]);
return LFS_ERR_CORRUPT; return LFS_ERR_CORRUPT;
} }
@@ -2423,6 +2472,39 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
return LFS_ERR_INVAL; 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; return 0;
} }

43
lfs.h
View File

@@ -50,15 +50,21 @@ typedef int32_t lfs_soff_t;
typedef uint32_t lfs_block_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 // Max name size in bytes
#ifndef LFS_NAME_MAX #ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 255 #define LFS_NAME_MAX 255
#endif #endif
#ifndef LFS_INLINE_MAX
#define LFS_INLINE_MAX 255
#endif
// Possible error codes, these are negative to allow // Possible error codes, these are negative to allow
// valid positive return values // valid positive return values
enum lfs_error { enum lfs_error {
@@ -74,6 +80,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_NAMETOOLONG = -36, // File name too long
}; };
// File types // File types
@@ -102,10 +109,10 @@ enum lfs_open_flags {
LFS_O_APPEND = 0x0800, // Move to end of file on every write LFS_O_APPEND = 0x0800, // Move to end of file on every write
// internally used flags // internally used flags
LFS_F_DIRTY = 0x10000, // File does not match storage LFS_F_DIRTY = 0x010000, // File does not match storage
LFS_F_WRITING = 0x20000, // File has been written since last flush LFS_F_WRITING = 0x020000, // File has been written since last flush
LFS_F_READING = 0x40000, // File has been read since last flush LFS_F_READING = 0x040000, // File has been read since last flush
LFS_F_ERRED = 0x80000, // An error occured during write LFS_F_ERRED = 0x080000, // An error occured during write
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry 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. // Optional, statically allocated buffer for files. Must be program sized.
// If enabled, only one file may be opened at a time. // If enabled, only one file may be opened at a time.
void *file_buffer; 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 { typedef struct lfs_superblock {
struct lfs_disk_superblock { struct lfs_disk_superblock {
lfs_block_t root[2]; 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; uint32_t version;
lfs_size_t inline_size;
lfs_size_t attrs_size;
lfs_size_t name_size;
} d; } d;
} lfs_superblock_t; } lfs_superblock_t;
@@ -285,6 +304,10 @@ typedef struct lfs {
lfs_free_t free; lfs_free_t free;
bool deorphaned; bool deorphaned;
lfs_size_t inline_size;
lfs_size_t attrs_size;
lfs_size_t name_size;
} lfs_t; } lfs_t;