Added internal lfs_dir_set, an umbrella to dir append/update/remove operations

This move was surprisingly complex, but offers the ultimate opportunity for
code reuse in terms of resizable entries. Instead of needing to provide
separate functions for adding and removing entries, adding and removing
entries can just be viewed as changing an entry's size to-and-from zero.

Unfortunately, it's not _quite_ that simple, since append and remove
hide some relatively complex operations for when directory blocks
overflow or need to be cleaned up.

However, with enough shoehorning, and a new committer type that allows
specifying recursive commit lists (is this now a push-down automata?),
it does seem to be possible to shove all of the entry update logic into
a single function.

Sidenote, I switched back to an enum-based DSL, since the addition of a
recursive region opcode breaks the consistency of what needs to be
passed to the DSL callback functions. It's much simpler to handle each
opcode explicitly inside a recursive lfs_commit_region function.
This commit is contained in:
Christopher Haster
2018-03-27 17:57:07 -05:00
parent ad74825bcf
commit 955545839b

579
lfs.c
View File

@@ -152,6 +152,7 @@ static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *pcache,
lfs_off_t off, const void *buffer, lfs_size_t size) { lfs_off_t off, const void *buffer, lfs_size_t size) {
const uint8_t *data = buffer; const uint8_t *data = buffer;
LFS_ASSERT(block != 0xffffffff); LFS_ASSERT(block != 0xffffffff);
LFS_ASSERT(off + size <= lfs->cfg->block_size);
while (size > 0) { while (size > 0) {
if (block == pcache->block && off >= pcache->off && if (block == pcache->block && off >= pcache->off &&
@@ -483,83 +484,93 @@ static int lfs_dir_fetch(lfs_t *lfs,
return 0; return 0;
} }
struct lfs_commit {
uint32_t crc;
lfs_block_t block;
lfs_off_t off;
};
static int lfs_commit(lfs_t *lfs, struct lfs_commit *c,
const void *data, lfs_size_t size) {
lfs_crc(&c->crc, data, size);
int err = lfs_bd_prog(lfs, c->block, c->off, data, size);
c->off += size;
return err;
}
struct lfs_region { struct lfs_region {
lfs_off_t off; enum {
lfs_ssize_t diff; LFS_FROM_DROP,
LFS_FROM_MEM,
LFS_FROM_REGION,
} type;
int (*commit)(lfs_t *lfs, struct lfs_commit *c, lfs_off_t off;
const void *data, lfs_size_t size); const void *buffer;
const void *data; lfs_ssize_t size;
lfs_size_t size;
struct lfs_region *next;
}; };
static int lfs_commit_mem(lfs_t *lfs, struct lfs_commit *c, struct lfs_region_region {
const void *data, lfs_size_t size) {
return lfs_commit(lfs, c, data, size);
}
struct lfs_commit_disk {
lfs_block_t block; lfs_block_t block;
lfs_off_t off; lfs_off_t off;
struct lfs_region *regions; struct lfs_region *regions;
int count;
}; };
static int lfs_commit_disk(lfs_t *lfs, struct lfs_commit *c, static int lfs_commit_region(lfs_t *lfs,
const void *p, lfs_size_t size) { lfs_block_t oldblock, lfs_off_t oldoff,
const struct lfs_commit_disk *d = p; lfs_block_t newblock, lfs_off_t newoff,
lfs_off_t regionoff,
struct lfs_region *r = d->regions; const struct lfs_region *regions, int count,
lfs_off_t off = 0; lfs_size_t size, uint32_t *crc) {
while (true) { int i = 0;
if (r && r->off == off) { lfs_size_t end = newoff + size;
lfs_off_t orig = c->off; while (newoff < end) {
int err = r->commit(lfs, c, r->data, r->size); // commit from different types of regions
if (err) { if (i < count && regions[i].off == oldoff - regionoff) {
return err; switch (regions[i].type) {
case LFS_FROM_DROP: {
oldoff -= regions[i].size;
break;
}
case LFS_FROM_MEM: {
lfs_crc(crc, regions[i].buffer, regions[i].size);
int err = lfs_bd_prog(lfs, newblock, newoff,
regions[i].buffer, regions[i].size);
if (err) {
return err;
}
newoff += regions[i].size;
break;
}
case LFS_FROM_REGION: {
const struct lfs_region_region *disk = regions[i].buffer;
int err = lfs_commit_region(lfs,
disk->block, disk->off,
newblock, newoff,
disk->off, disk->regions, disk->count,
regions[i].size, crc);
if (err) {
return err;
}
newoff += regions[i].size;
break;
}
} }
off += (c->off - orig) - r->diff; i += 1;
r = r->next;
} else if (off < size) {
uint8_t data;
int err = lfs_bd_read(lfs, d->block, d->off + off, &data, 1);
if (err) {
return err;
}
err = lfs_commit(lfs, c, &data, 1);
if (err) {
return err;
}
off += 1;
} else { } else {
return 0; // copy data from old block if not covered by region
uint8_t data;
int err = lfs_bd_read(lfs, oldblock, oldoff, &data, 1);
if (err) {
return err;
}
lfs_crc(crc, &data, 1);
err = lfs_bd_prog(lfs, newblock, newoff, &data, 1);
if (err) {
return err;
}
oldoff += 1;
newoff += 1;
} }
} }
return 0;
} }
// TODO handle overflowing reads (zero?) 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) {
struct lfs_region *regions) {
// 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]};
lfs_size_t oldsize = (0x7fffffff & dir->d.size) - 4;
bool relocated = false; bool relocated = false;
// increment revision count // increment revision count
@@ -567,8 +578,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
// keep pairs in order such that pair[0] is most recent // keep pairs in order such that pair[0] is most recent
lfs_pairswap(dir->pair); lfs_pairswap(dir->pair);
for (struct lfs_region *r = regions; r; r = r->next) { for (int i = 0; i < count; i++) {
dir->d.size += r->diff; dir->d.size += regions[i].size;
} }
while (true) { while (true) {
@@ -581,19 +592,11 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
return err; return err;
} }
struct lfs_commit c = { // commit header
.crc = 0xffffffff, uint32_t crc = 0xffffffff;
.block = dir->pair[0],
.off = 0,
};
lfs_dir_tole32(&dir->d); lfs_dir_tole32(&dir->d);
err = lfs_commit_disk(lfs, &c, &(struct lfs_commit_disk){ lfs_crc(&crc, &dir->d, sizeof(dir->d));
oldpair[1], 0, err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d));
&(struct lfs_region){
0, 0,
lfs_commit_mem, &dir->d, sizeof(dir->d),
regions}}, oldsize);
lfs_dir_fromle32(&dir->d); lfs_dir_fromle32(&dir->d);
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
@@ -602,9 +605,25 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
return err; return err;
} }
c.crc = lfs_tole32(c.crc); // commit region
err = lfs_bd_prog(lfs, dir->pair[0], c.off, &c.crc, 4); err = lfs_commit_region(lfs,
c.crc = lfs_fromle32(c.crc); dir->pair[1], sizeof(dir->d),
dir->pair[0], sizeof(dir->d),
0, regions, count,
(0x7fffffff & dir->d.size)-sizeof(dir->d)-4,
&crc);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
}
return err;
}
// commit crc
crc = lfs_tole32(crc);
err = lfs_bd_prog(lfs, dir->pair[0],
(0x7fffffff & dir->d.size)-4, &crc, 4);
crc = lfs_fromle32(crc);
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
goto relocate; goto relocate;
@@ -628,7 +647,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
return err; return err;
} }
if (ncrc != c.crc) { if (ncrc != crc) {
goto relocate; goto relocate;
} }
} }
@@ -683,61 +702,106 @@ static int lfs_dir_get(lfs_t *lfs, const lfs_dir_t *dir,
return lfs_bd_read(lfs, dir->pair[0], off, buffer, size); return lfs_bd_read(lfs, dir->pair[0], off, buffer, size);
} }
static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, static int lfs_dir_set(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry,
lfs_entry_t *entry, struct lfs_region *regions) { struct lfs_region *regions, int count) {
// check if we fit, if top bit is set we do not and move on lfs_ssize_t diff = 0;
while (true) { for (int i = 0; i < count; i++) {
if ((0x7fffffff & dir->d.size) + entry->size <= lfs->cfg->block_size) { diff += regions[i].size;
entry->off = dir->d.size - 4; }
for (struct lfs_region *r = regions; r; r = r->next) {
r->off += entry->off;
}
lfs_entry_tole32(&entry->d); lfs_size_t oldsize = entry->size;
int err = lfs_dir_commit(lfs, dir, regions); if (entry->off == 0) {
lfs_entry_fromle32(&entry->d); entry->off = (0x7fffffff & dir->d.size) - 4;
return err; }
}
// we need to allocate a new dir block if ((0x7fffffff & dir->d.size) + diff > lfs->cfg->block_size) {
if (!(0x80000000 & dir->d.size)) { lfs_dir_t olddir = *dir;
lfs_dir_t olddir = *dir; lfs_off_t oldoff = entry->off;
int err = lfs_dir_alloc(lfs, dir);
if (oldsize) {
// mark as moving
uint8_t type;
int err = lfs_dir_get(lfs, &olddir, oldoff, &type, 1);
if (err) { if (err) {
return err; return err;
} }
dir->d.tail[0] = olddir.d.tail[0]; type |= LFS_STRUCT_MOVED;
dir->d.tail[1] = olddir.d.tail[1]; err = lfs_dif_commit(lfs, &olddir, (struct lfs_region[]){
entry->off = dir->d.size - 4; {LFS_FROM_MEM, oldoff, &type, 1},
for (struct lfs_region *r = regions; r; r = r->next) { {LFS_FROM_DROP, oldoff, NULL, -1}}, 2);
r->off += entry->off;
}
lfs_entry_tole32(&entry->d);
err = lfs_dir_commit(lfs, dir, regions);
lfs_entry_fromle32(&entry->d);
if (err) { if (err) {
return err; return err;
} }
olddir.d.size |= 0x80000000;
olddir.d.tail[0] = dir->pair[0];
olddir.d.tail[1] = dir->pair[1];
return lfs_dir_commit(lfs, &olddir, NULL);
} }
int err = lfs_dir_fetch(lfs, dir, dir->d.tail); lfs_dir_t pdir = olddir;
// find available block or create a new one
while ((0x7fffffff & dir->d.size) + oldsize + diff
> lfs->cfg->block_size) {
// we need to allocate a new dir block
if (!(0x80000000 & dir->d.size)) {
pdir = *dir;
int err = lfs_dir_alloc(lfs, dir);
if (err) {
return err;
}
dir->d.tail[0] = pdir.d.tail[0];
dir->d.tail[1] = pdir.d.tail[1];
break;
}
int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
if (err) {
return err;
}
}
// writing out new entry
entry->off = dir->d.size - 4;
entry->size += diff;
int err = lfs_dif_commit(lfs, dir, (struct lfs_region[]){
{LFS_FROM_REGION, entry->off, &(struct lfs_region_region){
olddir.pair[0], oldoff,
regions, count}, entry->size}}, 1);
if (err) { if (err) {
return err; return err;
} }
}
}
static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, // update pred dir, unless pred == old we can coalesce
const lfs_entry_t *entry) { if (!oldsize || lfs_paircmp(pdir.pair, olddir.pair) != 0) {
// check if we should just drop the directory block pdir.d.size |= 0x80000000;
if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 + entry->size) { pdir.d.tail[0] = dir->pair[0];
pdir.d.tail[1] = dir->pair[1];
err = lfs_dif_commit(lfs, &pdir, NULL, 0);
if (err) {
return err;
}
} else if (oldsize) {
olddir.d.size |= 0x80000000;
olddir.d.tail[0] = dir->pair[0];
olddir.d.tail[1] = dir->pair[1];
}
// remove old entry
if (oldsize) {
lfs_entry_t oldentry;
oldentry.off = oldoff;
err = lfs_dir_set(lfs, &olddir, &oldentry, (struct lfs_region[]){
{LFS_FROM_DROP, 0, NULL, -oldsize}}, 1);
if (err) {
return err;
}
}
goto shift;
}
if ((0x7fffffff & dir->d.size) + diff == sizeof(dir->d)+4) {
lfs_dir_t pdir; lfs_dir_t pdir;
int res = lfs_pred(lfs, dir->pair, &pdir); int res = lfs_pred(lfs, dir->pair, &pdir);
if (res < 0) { if (res < 0) {
@@ -748,27 +812,34 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir,
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];
return lfs_dir_commit(lfs, &pdir, NULL); int err = lfs_dif_commit(lfs, &pdir, NULL, 0);
if (err) {
return err;
}
goto shift;
} }
} }
// shift out the entry for (int i = 0; i < count; i++) {
int err = lfs_dir_commit(lfs, dir, regions[i].off += entry->off;
&(struct lfs_region){ }
entry->off, -entry->size,
lfs_commit_mem, NULL, 0}); int err = lfs_dif_commit(lfs, dir, regions, count);
if (err) { if (err) {
return err; return err;
} }
entry->size += diff;
shift:
// shift over any files/directories that are affected // shift over any files/directories that are affected
for (lfs_file_t *f = lfs->files; f; f = f->next) { for (lfs_file_t *f = lfs->files; f; f = f->next) {
if (lfs_paircmp(f->pair, dir->pair) == 0) { if (lfs_paircmp(f->pair, dir->pair) == 0) {
if (f->poff == entry->off) { if (f->poff == entry->off && entry->size == 0) {
f->pair[0] = 0xffffffff; f->pair[0] = 0xffffffff;
f->pair[1] = 0xffffffff; f->pair[1] = 0xffffffff;
} else if (f->poff > entry->off) { } else if (f->poff > entry->off) {
f->poff -= entry->size; f->poff += diff;
} }
} }
} }
@@ -776,8 +847,8 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir,
for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
if (lfs_paircmp(d->pair, dir->pair) == 0) { if (lfs_paircmp(d->pair, dir->pair) == 0) {
if (d->off > entry->off) { if (d->off > entry->off) {
d->off -= entry->size; d->off += diff;
d->pos -= entry->size; d->pos += diff;
} }
} }
} }
@@ -785,87 +856,6 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir,
return 0; return 0;
} }
static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir,
lfs_entry_t *entry, struct lfs_region *regions) {
lfs_ssize_t diff = 0;
for (struct lfs_region *r = regions; r; r = r->next) {
diff += r->diff;
}
// do we still fit?
if ((0x7fffffff & dir->d.size) + diff <= lfs->cfg->block_size) {
for (struct lfs_region *r = regions; r; r = r->next) {
r->off += entry->off;
}
lfs_entry_tole32(&entry->d);
int err = lfs_dir_commit(lfs, dir, regions);
lfs_entry_fromle32(&entry->d);
if (err) {
return err;
}
// shift over any files/directories that are affected
for (lfs_file_t *f = lfs->files; f; f = f->next) {
if (lfs_paircmp(f->pair, dir->pair) == 0) {
if (f->poff > entry->off) {
f->poff += diff;
}
}
}
for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
if (lfs_paircmp(d->pair, dir->pair) == 0) {
if (d->off > entry->off) {
d->off += diff;
d->pos += diff;
}
}
}
} else {
lfs_dir_t olddir = *dir;
lfs_entry_t oldentry = {
.off = entry->off,
.size = entry->size - diff,
.d.type = entry->d.type | LFS_STRUCT_MOVED, // TODO FIXME when changing type??
};
// mark as moving
int err = lfs_dir_commit(lfs, &olddir,
&(struct lfs_region){
oldentry.off, 0,
lfs_commit_mem, &oldentry.d.type, 1});
if (err) {
return err;
}
// append updated entry
lfs_entry_tole32(&entry->d);
err = lfs_dir_append(lfs, dir, entry,
&(struct lfs_region){
0, +entry->size,
lfs_commit_disk, &(struct lfs_commit_disk){
olddir.pair[0], entry->off, regions}, oldentry.size});
lfs_entry_fromle32(&entry->d);
if (err) {
return err;
}
// remove old entry
err = lfs_dir_fetch(lfs, &olddir, olddir.pair);
if (err) {
return err;
}
err = lfs_dir_remove(lfs, &olddir, &oldentry);
if (err) {
return err;
}
}
return 0;
}
static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
while (dir->off >= (0x7fffffff & dir->d.size)-4) { while (dir->off >= (0x7fffffff & dir->d.size)-4) {
if (!(0x80000000 & dir->d.size)) { if (!(0x80000000 & dir->d.size)) {
@@ -1039,7 +1029,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_dir_commit(lfs, &dir, NULL); err = lfs_dif_commit(lfs, &dir, NULL, 0);
if (err) { if (err) {
return err; return err;
} }
@@ -1050,18 +1040,13 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
entry.d.nlen = strlen(path); entry.d.nlen = strlen(path);
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 = 4 + entry.d.elen + entry.d.alen + entry.d.nlen; entry.size = 0;
cwd.d.tail[0] = dir.pair[0]; cwd.d.tail[0] = dir.pair[0];
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_append(lfs, &cwd, &entry, {LFS_FROM_MEM, 0, &entry.d, sizeof(entry.d)},
&(struct lfs_region){ {LFS_FROM_MEM, 0, path, entry.d.nlen}}, 2);
0, +sizeof(entry.d),
lfs_commit_mem, &entry.d, sizeof(entry.d),
&(struct lfs_region){
0, +entry.d.nlen,
lfs_commit_mem, path, entry.d.nlen}});
if (err) { if (err) {
return err; return err;
} }
@@ -1447,15 +1432,11 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
entry.d.elen = 0; entry.d.elen = 0;
entry.d.alen = 0; entry.d.alen = 0;
entry.d.nlen = strlen(path); entry.d.nlen = strlen(path);
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen; entry.size = 0;
err = lfs_dir_append(lfs, &cwd, &entry, err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
&(struct lfs_region){ {LFS_FROM_MEM, 0, &entry.d, 4},
0, +4, {LFS_FROM_MEM, 0, path, entry.d.nlen}}, 2);
lfs_commit_mem, &entry.d, 4,
&(struct lfs_region){
0, +entry.d.nlen,
lfs_commit_mem, path, entry.d.nlen}});
if (err) { if (err) {
return err; return err;
} }
@@ -1684,43 +1665,37 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
// TODO entry read function? // TODO entry read function?
lfs_entry_t entry = {.off = file->poff}; lfs_entry_t entry = {.off = file->poff};
err = lfs_dir_get(lfs, &cwd, err = lfs_dir_get(lfs, &cwd, entry.off, &entry.d, sizeof(entry.d));
entry.off, &entry.d, sizeof(entry.d));
lfs_entry_fromle32(&entry.d); lfs_entry_fromle32(&entry.d);
if (err) { if (err) {
return err; return err;
} }
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;
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
// either update the references or inline the whole file
if (!(file->flags & LFS_F_INLINE)) { if (!(file->flags & LFS_F_INLINE)) {
lfs_ssize_t diff = sizeof(entry.d)-4 - entry.d.elen;
entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG; entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG;
entry.d.elen = sizeof(entry.d)-4; entry.d.elen = sizeof(entry.d)-4;
entry.d.u.file.head = file->head; entry.d.u.file.head = file->head;
entry.d.u.file.size = file->size; entry.d.u.file.size = file->size;
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
// TODO combine down? err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
err = lfs_dir_update(lfs, &cwd, &entry, {LFS_FROM_MEM, 0, &entry.d, sizeof(entry.d)},
&(struct lfs_region){ {LFS_FROM_DROP, 0, NULL, -oldlen-4}}, 2);
0, diff,
lfs_commit_mem, &entry.d, sizeof(entry.d)});
if (err) { if (err) {
return err; return err;
} }
} else { } else {
lfs_ssize_t diff = file->size - entry.d.elen;
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;
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
err = lfs_dir_update(lfs, &cwd, &entry, err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
&(struct lfs_region){ {LFS_FROM_MEM, 0, &entry.d, 4},
0, 0, {LFS_FROM_MEM, 0, file->cache.buffer, file->size},
lfs_commit_mem, &entry.d, 4, {LFS_FROM_DROP, 0, NULL, -oldlen-4}}, 3);
&(struct lfs_region){
4, diff,
lfs_commit_mem, file->cache.buffer, file->size}});
if (err) { if (err) {
return err; return err;
} }
@@ -2098,7 +2073,8 @@ int lfs_remove(lfs_t *lfs, const char *path) {
} }
// remove the entry // remove the entry
err = lfs_dir_remove(lfs, &cwd, &entry); err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
{LFS_FROM_DROP, 0, NULL, -entry.size}}, 1);
if (err) { if (err) {
return err; return err;
} }
@@ -2114,7 +2090,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_dir_commit(lfs, &cwd, NULL); err = lfs_dif_commit(lfs, &cwd, NULL, 0);
if (err) { if (err) {
return err; return err;
} }
@@ -2181,10 +2157,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// mark as moving // mark as moving
oldentry.d.type |= LFS_STRUCT_MOVED; oldentry.d.type |= LFS_STRUCT_MOVED;
err = lfs_dir_update(lfs, &oldcwd, &oldentry, err = lfs_dir_set(lfs, &oldcwd, &oldentry, (struct lfs_region[]){
&(struct lfs_region){ {LFS_FROM_MEM, 0, &oldentry.d.type, 1},
0, 0, {LFS_FROM_DROP, 0, NULL, -1}}, 2);
lfs_commit_mem, &oldentry.d.type, 1});
oldentry.d.type &= ~LFS_STRUCT_MOVED; oldentry.d.type &= ~LFS_STRUCT_MOVED;
if (err) { if (err) {
return err; return err;
@@ -2200,42 +2175,22 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
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 = strlen(newpath);
newentry.size = 4 + newentry.d.elen + newentry.d.alen + newentry.d.nlen; if (!prevexists) {
newentry.size = 0;
}
if (prevexists) { lfs_size_t newsize = oldentry.size - oldentry.d.nlen + newentry.d.nlen;
err = lfs_dir_update(lfs, &newcwd, &newentry, err = lfs_dir_set(lfs, &newcwd, &newentry, (struct lfs_region[]){
&(struct lfs_region){ {LFS_FROM_REGION, 0, &(struct lfs_region_region){
0, newentry.size - preventry.size, oldcwd.pair[0], oldentry.off, (struct lfs_region[]){
lfs_commit_disk, &(struct lfs_commit_disk){ {LFS_FROM_MEM, 0, &newentry.d, 4},
oldcwd.pair[0], oldentry.off, {LFS_FROM_DROP, 0, NULL, -4},
&(struct lfs_region){ {LFS_FROM_MEM, newsize - newentry.d.nlen,
0, 0, newpath, newentry.d.nlen}}, 3},
lfs_commit_mem, &newentry.d, 4, newsize},
&(struct lfs_region){ {LFS_FROM_DROP, 0, NULL, -preventry.size}}, prevexists ? 2 : 1);
newentry.size - newentry.d.nlen, if (err) {
+newentry.d.nlen-oldentry.d.nlen, return err;
lfs_commit_mem, newpath, newentry.d.nlen}}},
oldentry.size});
if (err) {
return err;
}
} else {
err = lfs_dir_append(lfs, &newcwd, &newentry,
&(struct lfs_region){
0, +newentry.size,
lfs_commit_disk, &(struct lfs_commit_disk){
oldcwd.pair[0], oldentry.off,
&(struct lfs_region){
0, 0,
lfs_commit_mem, &newentry.d, 4,
&(struct lfs_region){
newentry.size - newentry.d.nlen,
+newentry.d.nlen-oldentry.d.nlen,
lfs_commit_mem, newpath, newentry.d.nlen}}},
oldentry.size});
if (err) {
return err;
}
} }
// update pair if newcwd == oldcwd // update pair if newcwd == oldcwd
@@ -2244,7 +2199,8 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
} }
// remove old entry // remove old entry
err = lfs_dir_remove(lfs, &oldcwd, &oldentry); err = lfs_dir_set(lfs, &oldcwd, &oldentry, (struct lfs_region[]){
{LFS_FROM_DROP, 0, NULL, -oldentry.size}}, 1);
if (err) { if (err) {
return err; return err;
} }
@@ -2260,7 +2216,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_dir_commit(lfs, &newcwd, NULL); err = lfs_dif_commit(lfs, &newcwd, NULL, 0);
if (err) { if (err) {
return err; return err;
} }
@@ -2370,7 +2326,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
return err; return err;
} }
err = lfs_dir_commit(lfs, &root, NULL); err = lfs_dif_commit(lfs, &root, NULL, 0);
if (err) { if (err) {
return err; return err;
} }
@@ -2394,21 +2350,14 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
superentry.d.alen = 0; superentry.d.alen = 0;
superentry.d.nlen = strlen("littlefs"); superentry.d.nlen = strlen("littlefs");
superentry.off = sizeof(superdir.d); superentry.off = sizeof(superdir.d);
superentry.size = 4 + superentry.d.elen + superentry.size = 0;
superentry.d.alen + superentry.d.nlen;
lfs_entry_tole32(&superentry.d); lfs_entry_tole32(&superentry.d);
lfs_superblock_tole32(&superblock.d); lfs_superblock_tole32(&superblock.d);
err = lfs_dir_append(lfs, &superdir, &superentry, err = lfs_dir_set(lfs, &superdir, &superentry, (struct lfs_region[]){
&(struct lfs_region){ {LFS_FROM_MEM, 0, &superentry.d, 4},
0, +4, {LFS_FROM_MEM, 0, &superblock.d, sizeof(superblock.d)},
lfs_commit_mem, &superentry.d, 4, {LFS_FROM_MEM, 0, "littlefs", superentry.d.nlen}}, 3);
&(struct lfs_region){
0, +sizeof(superblock.d),
lfs_commit_mem, &superblock.d, sizeof(superblock.d),
&(struct lfs_region){
0, +superentry.d.nlen,
lfs_commit_mem, "littlefs", superentry.d.nlen}}});
if (err) { if (err) {
return err; return err;
} }
@@ -2452,8 +2401,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
} }
err = lfs_dir_get(lfs, &dir, err = lfs_dir_get(lfs, &dir,
sizeof(dir.d) + 4 + sizeof(superblock.d), sizeof(dir.d)+4 + sizeof(superblock.d), magic, sizeof(magic));
magic, sizeof(magic));
if (err) { if (err) {
return err; return err;
} }
@@ -2671,11 +2619,9 @@ static int lfs_relocate(lfs_t *lfs,
// update disk, this creates a desync // update disk, this creates a desync
entry.d.u.dir[0] = newpair[0]; entry.d.u.dir[0] = newpair[0];
entry.d.u.dir[1] = newpair[1]; entry.d.u.dir[1] = newpair[1];
int err = lfs_dir_set(lfs, &parent, &entry, (struct lfs_region[]){
int err = lfs_dir_update(lfs, &parent, &entry, {LFS_FROM_MEM, 0, &entry.d, sizeof(entry.d)},
&(struct lfs_region){ {LFS_FROM_DROP, 0, NULL, (lfs_ssize_t)-sizeof(entry.d)}}, 2);
0, 0,
lfs_commit_mem, &entry.d, sizeof(entry.d)});
if (err) { if (err) {
return err; return err;
} }
@@ -2702,7 +2648,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_dir_commit(lfs, &parent, NULL); return lfs_dif_commit(lfs, &parent, NULL, 0);
} }
// couldn't find dir, must be new // couldn't find dir, must be new
@@ -2744,7 +2690,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_dir_commit(lfs, &pdir, NULL); err = lfs_dif_commit(lfs, &pdir, NULL, 0);
if (err) { if (err) {
return err; return err;
} }
@@ -2760,7 +2706,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_dir_commit(lfs, &pdir, NULL); err = lfs_dif_commit(lfs, &pdir, NULL, 0);
if (err) { if (err) {
return err; return err;
} }
@@ -2791,7 +2737,8 @@ int lfs_deorphan(lfs_t *lfs) {
if (moved) { if (moved) {
LFS_DEBUG("Found move %d %d", LFS_DEBUG("Found move %d %d",
entry.d.u.dir[0], entry.d.u.dir[1]); entry.d.u.dir[0], entry.d.u.dir[1]);
err = lfs_dir_remove(lfs, &cwd, &entry); err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
{LFS_FROM_DROP, 0, NULL, -entry.size}}, 1);
if (err) { if (err) {
return err; return err;
} }
@@ -2799,10 +2746,10 @@ int lfs_deorphan(lfs_t *lfs) {
LFS_DEBUG("Found partial move %d %d", LFS_DEBUG("Found partial move %d %d",
entry.d.u.dir[0], entry.d.u.dir[1]); entry.d.u.dir[0], entry.d.u.dir[1]);
entry.d.type &= ~LFS_STRUCT_MOVED; entry.d.type &= ~LFS_STRUCT_MOVED;
err = lfs_dir_update(lfs, &cwd, &entry, err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
&(struct lfs_region){ {LFS_FROM_MEM, 0, &entry.d, sizeof(entry.d)},
0, 0, {LFS_FROM_DROP, 0, NULL,
lfs_commit_mem, &entry.d, sizeof(entry.d)}); (lfs_ssize_t)-sizeof(entry.d)}}, 2);
if (err) { if (err) {
return err; return err;
} }