mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 00:38:29 +01:00
WIP added support for inline files up to 1023 bytes
This commit is contained in:
103
lfs.c
103
lfs.c
@@ -371,6 +371,26 @@ static void lfs_superblock_tole32(struct lfs_disk_superblock *d) {
|
|||||||
d->name_size = lfs_tole32(d->name_size);
|
d->name_size = lfs_tole32(d->name_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Other struct functions ///
|
||||||
|
static inline lfs_size_t lfs_entry_elen(const lfs_entry_t *entry) {
|
||||||
|
return (lfs_size_t)(entry->d.elen) |
|
||||||
|
((lfs_size_t)(entry->d.alen & 0xc0) << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline lfs_size_t lfs_entry_alen(const lfs_entry_t *entry) {
|
||||||
|
return entry->d.alen & 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline lfs_size_t lfs_entry_nlen(const lfs_entry_t *entry) {
|
||||||
|
return entry->d.nlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline lfs_size_t lfs_entry_size(const lfs_entry_t *entry) {
|
||||||
|
return 4 + lfs_entry_elen(entry) +
|
||||||
|
lfs_entry_alen(entry) +
|
||||||
|
lfs_entry_nlen(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Metadata pair and directory operations ///
|
/// Metadata pair and directory operations ///
|
||||||
static inline void lfs_pairswap(lfs_block_t pair[2]) {
|
static inline void lfs_pairswap(lfs_block_t pair[2]) {
|
||||||
@@ -563,7 +583,7 @@ static int lfs_commit_region(lfs_t *lfs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lfs_dif_commit(lfs_t *lfs, lfs_dir_t *dir,
|
static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
|
||||||
const struct lfs_region *regions, int count) {
|
const struct lfs_region *regions, int count) {
|
||||||
// state for copying over
|
// state for copying over
|
||||||
const lfs_block_t oldpair[2] = {dir->pair[1], dir->pair[0]};
|
const lfs_block_t oldpair[2] = {dir->pair[1], dir->pair[0]};
|
||||||
@@ -723,7 +743,7 @@ static int lfs_dir_set(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type |= LFS_STRUCT_MOVED;
|
type |= LFS_STRUCT_MOVED;
|
||||||
err = lfs_dif_commit(lfs, &olddir, (struct lfs_region[]){
|
err = lfs_dir_commit(lfs, &olddir, (struct lfs_region[]){
|
||||||
{LFS_FROM_MEM, oldoff, &type, 1},
|
{LFS_FROM_MEM, oldoff, &type, 1},
|
||||||
{LFS_FROM_DROP, oldoff, NULL, -1}}, 2);
|
{LFS_FROM_DROP, oldoff, NULL, -1}}, 2);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -759,7 +779,7 @@ static int lfs_dir_set(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry,
|
|||||||
// writing out new entry
|
// writing out new entry
|
||||||
entry->off = dir->d.size - 4;
|
entry->off = dir->d.size - 4;
|
||||||
entry->size += diff;
|
entry->size += diff;
|
||||||
int err = lfs_dif_commit(lfs, dir, (struct lfs_region[]){
|
int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){
|
||||||
{LFS_FROM_REGION, entry->off, &(struct lfs_region_region){
|
{LFS_FROM_REGION, entry->off, &(struct lfs_region_region){
|
||||||
olddir.pair[0], oldoff,
|
olddir.pair[0], oldoff,
|
||||||
regions, count}, entry->size}}, 1);
|
regions, count}, entry->size}}, 1);
|
||||||
@@ -773,7 +793,7 @@ static int lfs_dir_set(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry,
|
|||||||
pdir.d.tail[0] = dir->pair[0];
|
pdir.d.tail[0] = dir->pair[0];
|
||||||
pdir.d.tail[1] = dir->pair[1];
|
pdir.d.tail[1] = dir->pair[1];
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &pdir, NULL, 0);
|
err = lfs_dir_commit(lfs, &pdir, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -808,7 +828,7 @@ static int lfs_dir_set(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry,
|
|||||||
pdir.d.size &= dir->d.size | 0x7fffffff;
|
pdir.d.size &= dir->d.size | 0x7fffffff;
|
||||||
pdir.d.tail[0] = dir->d.tail[0];
|
pdir.d.tail[0] = dir->d.tail[0];
|
||||||
pdir.d.tail[1] = dir->d.tail[1];
|
pdir.d.tail[1] = dir->d.tail[1];
|
||||||
int err = lfs_dif_commit(lfs, &pdir, NULL, 0);
|
int err = lfs_dir_commit(lfs, &pdir, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -820,7 +840,7 @@ static int lfs_dir_set(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry,
|
|||||||
regions[i].off += entry->off;
|
regions[i].off += entry->off;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = lfs_dif_commit(lfs, dir, regions, count);
|
int err = lfs_dir_commit(lfs, dir, regions, count);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -875,7 +895,7 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry->off = dir->off;
|
entry->off = dir->off;
|
||||||
entry->size = 4 + entry->d.elen + entry->d.alen + entry->d.nlen;
|
entry->size = lfs_entry_size(entry);
|
||||||
dir->off += entry->size;
|
dir->off += entry->size;
|
||||||
dir->pos += entry->size;
|
dir->pos += entry->size;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1031,7 +1051,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
|
|||||||
dir.d.tail[0] = cwd.d.tail[0];
|
dir.d.tail[0] = cwd.d.tail[0];
|
||||||
dir.d.tail[1] = cwd.d.tail[1];
|
dir.d.tail[1] = cwd.d.tail[1];
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &dir, NULL, 0);
|
err = lfs_dir_commit(lfs, &dir, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1156,7 +1176,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
|
|||||||
if (entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
|
if (entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
|
||||||
info->size = entry.d.u.file.size;
|
info->size = entry.d.u.file.size;
|
||||||
} else if (entry.d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
|
} else if (entry.d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
|
||||||
info->size = entry.d.elen;
|
info->size = lfs_entry_elen(&entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = lfs_dir_get(lfs, dir,
|
int err = lfs_dir_get(lfs, dir,
|
||||||
@@ -1470,29 +1490,22 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO combine these below?
|
|
||||||
// setup file struct
|
// setup file struct
|
||||||
file->pair[0] = cwd.pair[0];
|
file->pair[0] = cwd.pair[0];
|
||||||
file->pair[1] = cwd.pair[1];
|
file->pair[1] = cwd.pair[1];
|
||||||
file->poff = entry.off;
|
file->poff = entry.off;
|
||||||
file->head = entry.d.u.file.head;
|
|
||||||
file->size = entry.d.u.file.size;
|
|
||||||
file->flags = flags;
|
file->flags = flags;
|
||||||
file->pos = 0;
|
file->pos = 0;
|
||||||
|
|
||||||
if (flags & LFS_O_TRUNC) {
|
// calculate max inline size based on the size of the entry
|
||||||
if (file->size != 0) {
|
file->inline_size = lfs_min(lfs->inline_size,
|
||||||
file->flags |= LFS_F_DIRTY;
|
lfs->cfg->block_size - (sizeof(cwd.d)+4) -
|
||||||
}
|
(lfs_entry_size(&entry) - lfs_entry_elen(&entry)));
|
||||||
|
|
||||||
entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG;
|
|
||||||
entry.d.elen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// load inline files
|
|
||||||
if ((0x70 & entry.d.type) == LFS_STRUCT_INLINE) {
|
if ((0x70 & entry.d.type) == LFS_STRUCT_INLINE) {
|
||||||
|
// load inline files
|
||||||
file->head = 0xfffffffe;
|
file->head = 0xfffffffe;
|
||||||
file->size = entry.d.elen;
|
file->size = lfs_entry_elen(&entry);
|
||||||
file->flags |= LFS_F_INLINE;
|
file->flags |= LFS_F_INLINE;
|
||||||
file->cache.block = file->head;
|
file->cache.block = file->head;
|
||||||
file->cache.off = 0;
|
file->cache.off = 0;
|
||||||
@@ -1503,6 +1516,23 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
|
|||||||
lfs_free(file->cache.buffer);
|
lfs_free(file->cache.buffer);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// use ctz list from entry
|
||||||
|
file->head = entry.d.u.file.head;
|
||||||
|
file->size = entry.d.u.file.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate if requested
|
||||||
|
if (flags & LFS_O_TRUNC) {
|
||||||
|
if (file->size != 0) {
|
||||||
|
file->flags |= LFS_F_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->head = 0xfffffffe;
|
||||||
|
file->size = 0;
|
||||||
|
file->flags |= LFS_F_INLINE;
|
||||||
|
file->cache.block = file->head;
|
||||||
|
file->cache.off = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to list of files
|
// add to list of files
|
||||||
@@ -1676,8 +1706,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT((0xf & entry.d.type) == LFS_TYPE_REG);
|
LFS_ASSERT((0xf & entry.d.type) == LFS_TYPE_REG);
|
||||||
lfs_size_t oldlen = entry.d.elen;
|
lfs_size_t oldlen = lfs_entry_elen(&entry);
|
||||||
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
|
entry.size = lfs_entry_size(&entry);
|
||||||
|
|
||||||
// either update the references or inline the whole file
|
// either update the references or inline the whole file
|
||||||
if (!(file->flags & LFS_F_INLINE)) {
|
if (!(file->flags & LFS_F_INLINE)) {
|
||||||
@@ -1694,7 +1724,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG;
|
entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG;
|
||||||
entry.d.elen = file->size;
|
entry.d.elen = file->size & 0xff;
|
||||||
|
entry.d.alen = (entry.d.alen & 0x3f) | ((file->size >> 2) & 0xc0);
|
||||||
|
|
||||||
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},
|
||||||
@@ -1812,7 +1843,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
|
|||||||
// 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_size) {
|
file->pos + nsize >= file->inline_size) {
|
||||||
file->block = 0xfffffffe;
|
file->block = 0xfffffffe;
|
||||||
file->off = file->pos;
|
file->off = file->pos;
|
||||||
|
|
||||||
@@ -2024,7 +2055,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
|
|||||||
if (entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
|
if (entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
|
||||||
info->size = entry.d.u.file.size;
|
info->size = entry.d.u.file.size;
|
||||||
} else if (entry.d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
|
} else if (entry.d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
|
||||||
info->size = entry.d.elen;
|
info->size = lfs_entry_elen(&entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lfs_paircmp(entry.d.u.dir, lfs->root) == 0) {
|
if (lfs_paircmp(entry.d.u.dir, lfs->root) == 0) {
|
||||||
@@ -2093,7 +2124,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
|||||||
cwd.d.tail[0] = dir.d.tail[0];
|
cwd.d.tail[0] = dir.d.tail[0];
|
||||||
cwd.d.tail[1] = dir.d.tail[1];
|
cwd.d.tail[1] = dir.d.tail[1];
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &cwd, NULL, 0);
|
err = lfs_dir_commit(lfs, &cwd, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2224,7 +2255,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|||||||
newcwd.d.tail[0] = dir.d.tail[0];
|
newcwd.d.tail[0] = dir.d.tail[0];
|
||||||
newcwd.d.tail[1] = dir.d.tail[1];
|
newcwd.d.tail[1] = dir.d.tail[1];
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &newcwd, NULL, 0);
|
err = lfs_dir_commit(lfs, &newcwd, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2354,7 +2385,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &root, NULL, 0);
|
err = lfs_dir_commit(lfs, &root, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2436,14 +2467,14 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
memset(&superblock.d, 0, sizeof(superblock.d));
|
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(dir.d)+4, &superblock.d,
|
||||||
lfs_min(sizeof(superblock.d), entry.d.elen));
|
lfs_min(sizeof(superblock.d), lfs_entry_elen(&entry)));
|
||||||
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+entry.d.elen+entry.d.alen, magic,
|
sizeof(dir.d)+lfs_entry_size(&entry)-entry.d.nlen, magic,
|
||||||
lfs_min(sizeof(magic), entry.d.nlen));
|
lfs_min(sizeof(magic), entry.d.nlen));
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -2536,7 +2567,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dir.off += 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
|
dir.off += lfs_entry_size(&entry);
|
||||||
if ((0x70 & entry.d.type) == LFS_STRUCT_CTZ) {
|
if ((0x70 & entry.d.type) == LFS_STRUCT_CTZ) {
|
||||||
err = lfs_ctz_traverse(lfs, &lfs->rcache, NULL,
|
err = lfs_ctz_traverse(lfs, &lfs->rcache, NULL,
|
||||||
entry.d.u.file.head, entry.d.u.file.size, cb, data);
|
entry.d.u.file.head, entry.d.u.file.size, cb, data);
|
||||||
@@ -2720,7 +2751,7 @@ static int lfs_relocate(lfs_t *lfs,
|
|||||||
parent.d.tail[0] = newpair[0];
|
parent.d.tail[0] = newpair[0];
|
||||||
parent.d.tail[1] = newpair[1];
|
parent.d.tail[1] = newpair[1];
|
||||||
|
|
||||||
return lfs_dif_commit(lfs, &parent, NULL, 0);
|
return lfs_dir_commit(lfs, &parent, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// couldn't find dir, must be new
|
// couldn't find dir, must be new
|
||||||
@@ -2762,7 +2793,7 @@ int lfs_deorphan(lfs_t *lfs) {
|
|||||||
pdir.d.tail[0] = cwd.d.tail[0];
|
pdir.d.tail[0] = cwd.d.tail[0];
|
||||||
pdir.d.tail[1] = cwd.d.tail[1];
|
pdir.d.tail[1] = cwd.d.tail[1];
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &pdir, NULL, 0);
|
err = lfs_dir_commit(lfs, &pdir, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2778,7 +2809,7 @@ int lfs_deorphan(lfs_t *lfs) {
|
|||||||
pdir.d.tail[0] = entry.d.u.dir[0];
|
pdir.d.tail[0] = entry.d.u.dir[0];
|
||||||
pdir.d.tail[1] = entry.d.u.dir[1];
|
pdir.d.tail[1] = entry.d.u.dir[1];
|
||||||
|
|
||||||
err = lfs_dif_commit(lfs, &pdir, NULL, 0);
|
err = lfs_dir_commit(lfs, &pdir, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
7
lfs.h
7
lfs.h
@@ -52,17 +52,17 @@ typedef uint32_t lfs_block_t;
|
|||||||
|
|
||||||
// Maximum inline file size in bytes
|
// Maximum inline file size in bytes
|
||||||
#ifndef LFS_INLINE_MAX
|
#ifndef LFS_INLINE_MAX
|
||||||
#define LFS_INLINE_MAX 255
|
#define LFS_INLINE_MAX 0x3ff
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Maximum size of all attributes per file in bytes
|
// Maximum size of all attributes per file in bytes
|
||||||
#ifndef LFS_ATTRS_MAX
|
#ifndef LFS_ATTRS_MAX
|
||||||
#define LFS_ATTRS_MAX 255
|
#define LFS_ATTRS_MAX 0x3f
|
||||||
#endif
|
#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 0xff
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Possible error codes, these are negative to allow
|
// Possible error codes, these are negative to allow
|
||||||
@@ -248,6 +248,7 @@ typedef struct lfs_file {
|
|||||||
lfs_size_t size;
|
lfs_size_t size;
|
||||||
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
lfs_size_t inline_size;
|
||||||
lfs_off_t pos;
|
lfs_off_t pos;
|
||||||
lfs_block_t block;
|
lfs_block_t block;
|
||||||
lfs_off_t off;
|
lfs_off_t off;
|
||||||
|
|||||||
Reference in New Issue
Block a user