More testing progress, combined dir/commit traversal

Passing more tests now with the journalling change, but still have more
work to do.

The most humorous bug was a bug where during the three step move
process, the entry move logic would dumbly copy over any tags associated
with the moving entry, including the tag used to temporarily mark the
entry as "moving".

Also combined dir and commit traversal using a "stop_at_commit" flag in
directory struct as a short-term hack to combine the code paths.
This commit is contained in:
Christopher Haster
2018-05-27 10:15:28 -05:00
parent 0405ceb171
commit 0bdaeb7f8b
3 changed files with 350 additions and 303 deletions

643
lfs.c
View File

@@ -264,7 +264,7 @@ int lfs_fs_traverse(lfs_t *lfs,
static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_dir_t *pdir); static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_dir_t *pdir);
static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2], static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
lfs_dir_t *parent, lfs_entry_t *entry); lfs_dir_t *parent, lfs_entry_t *entry);
static int lfs_moved(lfs_t *lfs, const lfs_block_t pair[2]); static int lfs_moved(lfs_t *lfs, lfs_dir_t *fromdir, uint16_t fromid);
static int lfs_relocate(lfs_t *lfs, static int lfs_relocate(lfs_t *lfs,
const lfs_block_t oldpair[2], const lfs_block_t newpair[2]); const lfs_block_t oldpair[2], const lfs_block_t newpair[2]);
int lfs_deorphan(lfs_t *lfs); int lfs_deorphan(lfs_t *lfs);
@@ -473,40 +473,6 @@ struct lfs_commit {
} filter; } filter;
}; };
static int lfs_commit_traverse(lfs_t *lfs, struct lfs_commit *commit,
int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry), void *data) {
// TODO duplicate this? move it to dir?
// iterate over dir block backwards (for faster lookups)
lfs_block_t block = commit->block;
lfs_off_t off = commit->off;
lfs_tag_t tag = commit->ptag;
while (off != sizeof(uint32_t)) {
// TODO rm me
printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, block, off-lfs_tag_size(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
int err = cb(lfs, data, (lfs_entry_t){
(0x80000000 | tag),
.u.d.block=block,
.u.d.off=off-lfs_tag_size(tag)});
if (err) {
return err;
}
LFS_ASSERT(off > sizeof(tag)+lfs_tag_size(tag));
off -= sizeof(tag)+lfs_tag_size(tag);
lfs_tag_t ntag;
err = lfs_bd_read(lfs, block, off, &ntag, sizeof(ntag));
if (err) {
return err;
}
tag ^= lfs_fromle32(ntag);
}
return 0;
}
//static int lfs_commit_compactcheck(lfs_t *lfs, void *p, lfs_entry_t entry) { //static int lfs_commit_compactcheck(lfs_t *lfs, void *p, lfs_entry_t entry) {
// struct lfs_commit *commit = p; // struct lfs_commit *commit = p;
// if (lfs_tag_id(entry.tag) != commit->compact.id) { // if (lfs_tag_id(entry.tag) != commit->compact.id) {
@@ -527,7 +493,7 @@ static int lfs_commit_commit(lfs_t *lfs,
return 0; return 0;
} }
uint16_t id = lfs_tag_id(entry.tag) - commit->filter.begin; uint16_t id = lfs_tag_id(entry.tag) - commit->filter.begin;
entry.tag = (id << 12) | (entry.tag & 0xffe00fff); entry.tag = lfs_mktag(0, id, 0) | (entry.tag & 0xffe00fff);
// check if we fit // check if we fit
lfs_size_t size = lfs_tag_size(entry.tag); lfs_size_t size = lfs_tag_size(entry.tag);
@@ -537,7 +503,7 @@ static int lfs_commit_commit(lfs_t *lfs,
// write out tag // write out tag
// TODO rm me // TODO rm me
printf("tag w %#010x (%x:%x %03x %03x %03x)\n", entry.tag, commit->block, commit->off+sizeof(lfs_tag_t), lfs_tag_type(entry.tag), lfs_tag_id(entry.tag), lfs_tag_size(entry.tag)); //printf("tag w %#010x (%x:%x %03x %03x %03x)\n", entry.tag, commit->block, commit->off+sizeof(lfs_tag_t), lfs_tag_type(entry.tag), lfs_tag_id(entry.tag), lfs_tag_size(entry.tag));
lfs_tag_t tag = lfs_tole32((entry.tag & 0x7fffffff) ^ commit->ptag); lfs_tag_t tag = lfs_tole32((entry.tag & 0x7fffffff) ^ commit->ptag);
lfs_crc(&commit->crc, &tag, sizeof(tag)); lfs_crc(&commit->crc, &tag, sizeof(tag));
int err = lfs_bd_prog(lfs, commit->block, commit->off, &tag, sizeof(tag)); int err = lfs_bd_prog(lfs, commit->block, commit->off, &tag, sizeof(tag));
@@ -572,7 +538,7 @@ static int lfs_commit_commit(lfs_t *lfs,
} }
} }
commit->off += size; commit->off += size;
commit->ptag = entry.tag; commit->ptag = entry.tag & 0x7fffffff; // TODO do this once
return 0; return 0;
} }
@@ -595,7 +561,7 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) {
noff - (commit->off+sizeof(uint32_t))); noff - (commit->off+sizeof(uint32_t)));
// write out crc // write out crc
printf("tag w %#010x (%x:%x %03x %03x %03x)\n", tag, commit->block, commit->off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag)); //printf("tag w %#010x (%x:%x %03x %03x %03x)\n", tag, commit->block, commit->off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
uint32_t footer[2]; uint32_t footer[2];
footer[0] = lfs_tole32(tag ^ commit->ptag); footer[0] = lfs_tole32(tag ^ commit->ptag);
lfs_crc(&commit->crc, &footer[0], sizeof(footer[0])); lfs_crc(&commit->crc, &footer[0], sizeof(footer[0]));
@@ -641,10 +607,6 @@ static int lfs_commit_regions(lfs_t *lfs, void *p, struct lfs_commit *commit) {
return 0; return 0;
} }
// TODO redeclare
static int lfs_dir_traverse(lfs_t *lfs, lfs_dir_t *dir,
int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry),
void *data);
// committer for moves // committer for moves
struct lfs_commit_move { struct lfs_commit_move {
@@ -653,40 +615,31 @@ struct lfs_commit_move {
uint16_t from; uint16_t from;
uint16_t to; uint16_t to;
} id; } id;
uint16_t type;
struct lfs_commit *commit; struct lfs_commit *commit;
}; };
static int lfs_commit_movecheck(lfs_t *lfs, void *p, lfs_entry_t entry) { // TODO redeclare
static int lfs_dir_traverse(lfs_t *lfs, lfs_dir_t *dir,
int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry),
void *data);
static int lfs_dir_get(lfs_t *lfs, lfs_dir_t *dir,
uint32_t mask, lfs_entry_t *entry);
static int lfs_commit_movescan(lfs_t *lfs, void *p, lfs_entry_t entry) {
struct lfs_commit_move *move = p; struct lfs_commit_move *move = p;
if (lfs_tag_id(entry.tag) != move->id.to - move->commit->filter.begin) { if (lfs_tag_type(entry.tag) == LFS_TYPE_DELETE &&
return 1; lfs_tag_id(entry.tag) <= move->id.from) {
// something was deleted, we need to move around it
move->id.from += 1;
return 0;
} }
if (lfs_tag_type(entry.tag) & 0x100) { if (lfs_tag_type(entry.tag) == LFS_TYPE_MOVE) {
if (lfs_tag_type(entry.tag) == move->type) { // TODO need this?
return 2; // ignore moves
} return 0;
} else {
// TODO hmm
if (lfs_tag_subtype(entry.tag) == (move->type & 0x1f0)) {
return 2;
}
}
return 0;
}
static int lfs_commit_moveiter(lfs_t *lfs, void *p, lfs_entry_t entry) {
struct lfs_commit_move *move = p;
if (lfs_tag_type(entry.tag) == LFS_TYPE_DELETE) {
if (lfs_tag_id(entry.tag) <= move->id.from) {
// something was deleted, we need to move around it
move->id.from += 1;
}
} }
if (lfs_tag_id(entry.tag) != move->id.from) { if (lfs_tag_id(entry.tag) != move->id.from) {
@@ -694,28 +647,41 @@ static int lfs_commit_moveiter(lfs_t *lfs, void *p, lfs_entry_t entry) {
return 0; return 0;
} }
move->type = lfs_tag_type(entry.tag); // check if type has already been committed
int res = lfs_commit_traverse(lfs, move->commit, int err = lfs_dir_get(lfs,
lfs_commit_movecheck, move); &(lfs_dir_t){
if (res < 0) { .pair[0]=move->commit->block,
return res; .off=move->commit->off,
.etag=move->commit->ptag,
.stop_at_commit=true},
lfs_tag_type(entry.tag) & 0x100 ? 0x7ffff000 : 0x7c1ff000,
&(lfs_entry_t){
lfs_mktag(lfs_tag_type(entry.tag), move->id.to, 0)});
if (err && err != LFS_ERR_NOENT) {
return err;
} }
if (res == 2) { if (err != LFS_ERR_NOENT) {
// already committed // already committed
return 0; return 0;
} }
// update id and commit, as we are currently unique // update id and commit, as we are currently unique
entry.tag = (move->id.to << 12) | (entry.tag & 0xffe00fff); entry.tag = lfs_mktag(0, move->id.to, 0) | (entry.tag & 0xffe00fff);
return lfs_commit_commit(lfs, move->commit, entry); return lfs_commit_commit(lfs, move->commit, entry);
} }
// TODO change this to be special RAM-side type in linked list of commits?
static int lfs_commit_move(lfs_t *lfs, void *p, struct lfs_commit *commit) { static int lfs_commit_move(lfs_t *lfs, void *p, struct lfs_commit *commit) {
struct lfs_commit_move *move = p; struct lfs_commit_move *move = p;
move->commit = commit; move->commit = commit;
if (move->id.to < commit->filter.begin ||
move->id.to >= commit->filter.end) {
// skip if not in filter
return 0;
}
int err = lfs_dir_traverse(lfs, move->dir, lfs_commit_moveiter, move); int err = lfs_dir_traverse(lfs, move->dir, lfs_commit_movescan, move);
if (err < 0) { if (err < 0) {
return err; return err;
} }
@@ -759,6 +725,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry), void *data) { int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry), void *data) {
dir->pair[0] = pair[0]; dir->pair[0] = pair[0];
dir->pair[1] = pair[1]; dir->pair[1] = pair[1];
dir->stop_at_commit = false;
// find the block with the most recent revision // find the block with the most recent revision
uint32_t rev[2]; uint32_t rev[2];
@@ -812,7 +779,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
break; break;
} }
printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, dir->pair[0], off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag)); //printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, dir->pair[0], off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
if (lfs_tag_type(tag) == LFS_TYPE_CRC) { if (lfs_tag_type(tag) == LFS_TYPE_CRC) {
// check the crc entry // check the crc entry
uint32_t dcrc; uint32_t dcrc;
@@ -862,6 +829,9 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
if (lfs_tag_type(tag) == LFS_TYPE_DELETE) { if (lfs_tag_type(tag) == LFS_TYPE_DELETE) {
dir->count -= 1; dir->count -= 1;
if (dir->moveid != -1) {
//printf("RENAME DEL %d (%d)\n", lfs_tag_id(tag), dir->moveid);
}
if (lfs_tag_id(tag) == dir->moveid) { if (lfs_tag_id(tag) == dir->moveid) {
dir->moveid = -1; dir->moveid = -1;
} else if (lfs_tag_id(tag) < dir->moveid) { } else if (lfs_tag_id(tag) < dir->moveid) {
@@ -901,9 +871,41 @@ static int lfs_dir_fetch(lfs_t *lfs,
static int lfs_dir_traverse(lfs_t *lfs, lfs_dir_t *dir, static int lfs_dir_traverse(lfs_t *lfs, lfs_dir_t *dir,
int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry), void *data) { int (*cb)(lfs_t *lfs, void *data, lfs_entry_t entry), void *data) {
return lfs_commit_traverse(lfs, &(struct lfs_commit){ // iterate over dir block backwards (for faster lookups)
.block=dir->pair[0], .off=dir->off, .ptag=dir->etag}, lfs_block_t block = dir->pair[0];
cb, data); lfs_off_t off = dir->off;
lfs_tag_t tag = dir->etag;
while (off != sizeof(uint32_t)) {
// TODO rm me
//printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, block, off-lfs_tag_size(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
// TODO hmm
if (dir->stop_at_commit && lfs_tag_type(tag) == LFS_TYPE_CRC) {
break;
}
int err = cb(lfs, data, (lfs_entry_t){
(0x80000000 | tag),
.u.d.block=block,
.u.d.off=off-lfs_tag_size(tag)});
if (err) {
return err;
}
LFS_ASSERT(off > sizeof(tag)+lfs_tag_size(tag));
off -= sizeof(tag)+lfs_tag_size(tag);
lfs_tag_t ntag;
err = lfs_bd_read(lfs, block, off, &ntag, sizeof(ntag));
if (err) {
return err;
}
tag ^= lfs_fromle32(ntag);
}
return 0;
} }
//struct lfs_dir_commitmove { //struct lfs_dir_commitmove {
@@ -1159,6 +1161,7 @@ static int lfs_dir_commitwith(lfs_t *lfs, lfs_dir_t *dir,
int err = cb(lfs, data, &commit); int err = cb(lfs, data, &commit);
if (err) { if (err) {
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
lfs->pcache.block = 0xffffffff;
return lfs_dir_compact(lfs, dir, cb, data, dir, 0, dir->count); return lfs_dir_compact(lfs, dir, cb, data, dir, 0, dir->count);
} }
return err; return err;
@@ -1167,6 +1170,7 @@ static int lfs_dir_commitwith(lfs_t *lfs, lfs_dir_t *dir,
err = lfs_commit_crc(lfs, &commit); err = lfs_commit_crc(lfs, &commit);
if (err) { if (err) {
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
lfs->pcache.block = 0xffffffff;
return lfs_dir_compact(lfs, dir, cb, data, dir, 0, dir->count); return lfs_dir_compact(lfs, dir, cb, data, dir, 0, dir->count);
} }
return err; return err;
@@ -1203,11 +1207,14 @@ struct lfs_dir_getter {
static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_entry_t entry) { static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_entry_t entry) {
struct lfs_dir_getter *get = p; struct lfs_dir_getter *get = p;
if ((entry.tag & get->mask) == (get->tag & get->mask)) { if ((entry.tag & get->mask) == (get->tag & get->mask)) {
if (get->entry) { *get->entry = entry;
*get->entry = entry;
}
return true; return true;
} else if (lfs_tag_type(entry.tag) == LFS_TYPE_DELETE) {
if (lfs_tag_id(entry.tag) <= lfs_tag_id(get->tag)) {
get->tag += lfs_mktag(0, 1, 0);
}
} }
return false; return false;
@@ -1215,6 +1222,7 @@ static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_entry_t entry) {
static int lfs_dir_get(lfs_t *lfs, lfs_dir_t *dir, static int lfs_dir_get(lfs_t *lfs, lfs_dir_t *dir,
uint32_t mask, lfs_entry_t *entry) { uint32_t mask, lfs_entry_t *entry) {
uint16_t id = lfs_tag_id(entry->tag);
int res = lfs_dir_traverse(lfs, dir, lfs_dir_getter, int res = lfs_dir_traverse(lfs, dir, lfs_dir_getter,
&(struct lfs_dir_getter){mask, entry->tag, entry}); &(struct lfs_dir_getter){mask, entry->tag, entry});
if (res < 0) { if (res < 0) {
@@ -1225,6 +1233,18 @@ static int lfs_dir_get(lfs_t *lfs, lfs_dir_t *dir,
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
if (id == dir->moveid) {
int moved = lfs_moved(lfs, dir, dir->moveid);
if (moved < 0) {
return moved;
}
if (moved) {
return LFS_ERR_NOENT;
}
}
entry->tag = lfs_mktag(0, id, 0) | (entry->tag & 0xffe00fff);
return 0; return 0;
} }
@@ -1287,7 +1307,7 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_dir_t *dir,
} }
err = lfs_dir_getbuffer(lfs, dir, 0x7ffff000, &(lfs_entry_t){ err = lfs_dir_getbuffer(lfs, dir, 0x7ffff000, &(lfs_entry_t){
lfs_mktag(LFS_TYPE_NAME, id, lfs->cfg->name_size+1), lfs_mktag(LFS_TYPE_NAME, id, lfs->name_size+1),
.u.buffer=info->name}); .u.buffer=info->name});
if (err) { if (err) {
return err; return err;
@@ -1401,24 +1421,24 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
break; break;
} }
if (lfs_pairisnull(dir->tail)) { if (!dir->split) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
entry.u.pair[0] = dir->tail[0]; entry.u.pair[0] = dir->tail[0];
entry.u.pair[1] = dir->tail[1]; entry.u.pair[1] = dir->tail[1];
} }
// TODO handle moves if (find.id == dir->moveid) {
// // check that entry has not been moved int moved = lfs_moved(lfs, dir, dir->moveid);
// if (entry->d.type & LFS_STRUCT_MOVED) { if (moved < 0) {
// int moved = lfs_moved(lfs, &entry->d.u); return moved;
// if (moved < 0 || moved) { }
// return (moved < 0) ? moved : LFS_ERR_NOENT;
// } if (moved) {
// return LFS_ERR_NOENT;
// entry->d.type &= ~LFS_STRUCT_MOVED; }
// } }
*id = find.id; *id = find.id;
find.name += find.len; find.name += find.len;
@@ -2319,11 +2339,15 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
return err; return err;
} }
cwd.tail[0] = dir.pair[0];
cwd.tail[1] = dir.pair[1];
err = lfs_dir_commit(lfs, &cwd, &(lfs_entrylist_t){ err = lfs_dir_commit(lfs, &cwd, &(lfs_entrylist_t){
{lfs_mktag(LFS_TYPE_NAME, id, nlen), {lfs_mktag(LFS_TYPE_NAME, id, nlen),
.u.buffer=(void*)path}, &(lfs_entrylist_t){ .u.buffer=(void*)path}, &(lfs_entrylist_t){
{lfs_mktag(LFS_TYPE_DIR | LFS_STRUCT_DIR, id, sizeof(dir.pair)), {lfs_mktag(LFS_TYPE_DIR | LFS_STRUCT_DIR, id, sizeof(dir.pair)),
.u.buffer=dir.pair}}}); .u.buffer=dir.pair}, &(lfs_entrylist_t){
{lfs_mktag(LFS_TYPE_SOFTTAIL, 0x1ff, sizeof(cwd.tail)),
.u.buffer=cwd.tail}}}});
// TODO need ack here? // TODO need ack here?
lfs_alloc_ack(lfs); lfs_alloc_ack(lfs);
@@ -3571,198 +3595,209 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
return lfs_dir_getinfo(lfs, &cwd, id, info); return lfs_dir_getinfo(lfs, &cwd, id, info);
} }
// int lfs_remove(lfs_t *lfs, const char *path) {
//int lfs_remove(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron
// // deorphan if we haven't yet, needed at most once after poweron if (!lfs->deorphaned) {
// if (!lfs->deorphaned) { int err = lfs_deorphan(lfs);
// int err = lfs_deorphan(lfs); if (err) {
// if (err) { return err;
// return err; }
// } }
// }
// lfs_dir_t cwd;
// lfs_dir_t cwd; int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
// int err = lfs_dir_fetch(lfs, &cwd, lfs->root); if (err) {
// if (err) { return err;
// return err; }
// }
// int16_t id;
// lfs_entry_t entry; err = lfs_dir_find(lfs, &cwd, &path, &id);
// err = lfs_dir_find(lfs, &cwd, &entry, &path); if (err) {
// if (err) { return err;
// return err; }
// }
// // grab entry to see if we're dealing with a dir
// lfs_dir_t dir; lfs_entry_t entry;
// if ((0xf & entry.d.type) == LFS_TYPE_DIR) { err = lfs_dir_getentry(lfs, &cwd, 0x701ff000,
// // must be empty before removal, checking size lfs_mktag(LFS_TYPE_REG, id, 0), &entry);
// // without masking top bit checks for any case where if (err) {
// // dir is not empty return err;
// err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir); }
// if (err) {
// return err; if (lfs_tag_subtype(entry.tag) == LFS_TYPE_DIR) {
// } else if (dir.d.size != sizeof(dir.d)+4) { lfs_dir_t dir;
// return LFS_ERR_NOTEMPTY; // must be empty before removal
// } err = lfs_dir_fetch(lfs, &dir, entry.u.pair);
// } if (err) {
// return err;
// // remove the entry }
// err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){
// {LFS_FROM_MEM, 0, entry.size, NULL, 0}}, 1); if (dir.count > 0 || dir.split) {
// if (err) { return LFS_ERR_NOTEMPTY;
// return err; }
// } }
//
// // if we were a directory, find pred, replace tail // delete the entry
// if ((0xf & entry.d.type) == LFS_TYPE_DIR) { err = lfs_dir_delete(lfs, &cwd, id);
if (err) {
return err;
}
// if we were a directory, find pred, replace tail
// TODO can this just deorphan?
if (lfs_tag_subtype(entry.tag) == LFS_TYPE_DIR) {
err = lfs_deorphan(lfs);
if (err) {
return err;
}
}
// if (lfs_tag_subtype(entry.tag) == LFS_TYPE_DIR) {
// int res = lfs_pred(lfs, dir.pair, &cwd); // int res = lfs_pred(lfs, dir.pair, &cwd);
// if (res < 0) { // if (res < 0) {
// return res; // return res;
// } // }
// //
// LFS_ASSERT(res); // must have pred // LFS_ASSERT(res); // must have pred
// cwd.d.tail[0] = dir.d.tail[0]; // cwd.tail[0] = dir.tail[0];
// cwd.d.tail[1] = dir.d.tail[1]; // cwd.tail[1] = dir.tail[1];
// //
// err = lfs_dir_commit(lfs, &cwd, NULL, 0); // err = lfs_dir_commit(lfs, &cwd, NULL, 0);
// if (err) { // if (err) {
// return err; // return err;
// } // }
// } // }
//
// return 0; return 0;
//} }
//
//int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// // deorphan if we haven't yet, needed at most once after poweron // deorphan if we haven't yet, needed at most once after poweron
// if (!lfs->deorphaned) { if (!lfs->deorphaned) {
// int err = lfs_deorphan(lfs); int err = lfs_deorphan(lfs);
// if (err) { if (err) {
// return err; return err;
// } }
// } }
//
// // find old entry // find old entry
// lfs_dir_t oldcwd; lfs_dir_t oldcwd;
// int err = lfs_dir_fetch(lfs, &oldcwd, lfs->root); int16_t oldid;
// if (err) { int err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldid);
// return err; if (err) {
// } return err;
// }
// lfs_entry_t oldentry;
// err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath); lfs_entry_t oldentry;
// if (err) { err = lfs_dir_getentry(lfs, &oldcwd, 0x701ff000,
// return err; lfs_mktag(LFS_TYPE_REG, oldid, 0), &oldentry);
// } if (err) {
// return err;
// // allocate new entry }
// lfs_dir_t newcwd;
// err = lfs_dir_fetch(lfs, &newcwd, lfs->root); // find new entry
// if (err) { lfs_dir_t newcwd;
// return err; int16_t newid;
// } err = lfs_dir_find(lfs, &newcwd, &newpath, &newid);
// if (err && err != LFS_ERR_NOENT) {
// lfs_entry_t preventry; return err;
// err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath); }
// if (err && (err != LFS_ERR_NOENT || strchr(newpath, '/') != NULL)) {
// return err; bool prevexists = (err != LFS_ERR_NOENT);
// } bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
// lfs_entry_t preventry;
// bool prevexists = (err != LFS_ERR_NOENT); if (prevexists) {
// bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0); // get prev entry, check that we have same type
// err = lfs_dir_getentry(lfs, &newcwd, 0x701ff000,
// // check that name fits lfs_mktag(LFS_TYPE_REG, newid, 0), &preventry);
// lfs_size_t nlen = strlen(newpath); if (err) {
// if (nlen > lfs->name_size) { return err;
// return LFS_ERR_NAMETOOLONG; }
// }
// if (lfs_tag_subtype(preventry.tag) != lfs_tag_subtype(oldentry.tag)) {
// if (oldentry.size - oldentry.d.nlen + nlen > lfs->cfg->block_size) { return LFS_ERR_ISDIR;
// return LFS_ERR_NOSPC; }
// }
// if (lfs_tag_subtype(preventry.tag) == LFS_TYPE_DIR) {
// // must have same type lfs_dir_t prevdir;
// if (prevexists && preventry.d.type != oldentry.d.type) { // must be empty before removal
// return LFS_ERR_ISDIR; err = lfs_dir_fetch(lfs, &prevdir, preventry.u.pair);
// } if (err) {
// return err;
// lfs_dir_t dir; }
// if (prevexists && (0xf & preventry.d.type) == LFS_TYPE_DIR) {
// // must be empty before removal, checking size if (prevdir.count > 0 || prevdir.split) {
// // without masking top bit checks for any case where return LFS_ERR_NOTEMPTY;
// // dir is not empty }
// err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir); }
// if (err) { } else {
// return err; // check that name fits
// } else if (dir.d.size != sizeof(dir.d)+4) { lfs_size_t nlen = strlen(newpath);
// return LFS_ERR_NOTEMPTY; if (nlen > lfs->name_size) {
// } return LFS_ERR_NAMETOOLONG;
// } }
//
// // mark as moving // get next id
// oldentry.d.type |= LFS_STRUCT_MOVED; err = lfs_dir_append(lfs, &newcwd, &newid);
// err = lfs_dir_set(lfs, &oldcwd, &oldentry, (struct lfs_region[]){ if (err) {
// {LFS_FROM_MEM, 0, 1, &oldentry.d.type, 1}}, 1); return err;
// oldentry.d.type &= ~LFS_STRUCT_MOVED; }
// if (err) { }
// return err;
// } // mark as moving
// //printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
// // update pair if newcwd == oldcwd err = lfs_dir_commit(lfs, &oldcwd, &(lfs_entrylist_t){
// if (samepair) { {lfs_mktag(LFS_TYPE_MOVE, oldid, 0)}});
// newcwd = oldcwd; if (err) {
// } return err;
// }
// // move to new location
// lfs_entry_t newentry = preventry; if (samepair) {
// newentry.d = oldentry.d; // update pair if newcwd == oldcwd
// newentry.d.type &= ~LFS_STRUCT_MOVED; newcwd = oldcwd;
// newentry.d.nlen = nlen; }
// newentry.size = prevexists ? preventry.size : 0;
// // move to new location
// lfs_size_t newsize = oldentry.size - oldentry.d.nlen + newentry.d.nlen; // TODO NAME?????
// err = lfs_dir_set(lfs, &newcwd, &newentry, (struct lfs_region[]){ // TODO HAH, move doesn't want to override things (due
// {LFS_FROM_REGION, 0, prevexists ? preventry.size : 0, // to its use in compaction), but that's _exactly_ what we want here
// &(struct lfs_region_region){ err = lfs_dir_commitwith(lfs, &newcwd, lfs_commit_move,
// oldcwd.pair[0], oldentry.off, (struct lfs_region[]){ &(struct lfs_commit_move){.dir=&oldcwd, .id={oldid, newid}});
// {LFS_FROM_MEM, 0, 4, &newentry.d, 4}, if (err) {
// {LFS_FROM_MEM, newsize-nlen, 0, newpath, nlen}}, 2}, return err;
// newsize}}, 1); }
// if (err) { // TODO NONONONONO
// return err; // TODO also don't call strlen twice (see prev name check)
// } err = lfs_dir_commit(lfs, &newcwd, &(lfs_entrylist_t){
// {lfs_mktag(LFS_TYPE_NAME, newid, strlen(newpath)),
// // update pair if newcwd == oldcwd .u.buffer=(void*)newpath}});
// if (samepair) { if (err) {
// oldcwd = newcwd; return err;
// } }
//
// // remove old entry if (samepair) {
// err = lfs_dir_set(lfs, &oldcwd, &oldentry, (struct lfs_region[]){ // update pair if newcwd == oldcwd
// {LFS_FROM_MEM, 0, oldentry.size, NULL, 0}}, 1); oldcwd = newcwd;
// if (err) { }
// return err;
// } // remove old entry
// //printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
// // if we were a directory, find pred, replace tail err = lfs_dir_delete(lfs, &oldcwd, oldid);
// if (prevexists && (0xf & preventry.d.type) == LFS_TYPE_DIR) { if (err) {
// int res = lfs_pred(lfs, dir.pair, &newcwd); return err;
// if (res < 0) { }
// return res;
// } // if we were a directory, find pred, replace tail
// // TODO can this just deorphan?
// LFS_ASSERT(res); // must have pred if (prevexists && lfs_tag_subtype(preventry.tag) == LFS_TYPE_DIR) {
// newcwd.d.tail[0] = dir.d.tail[0]; err = lfs_deorphan(lfs);
// newcwd.d.tail[1] = dir.d.tail[1]; if (err) {
// return err;
// err = lfs_dir_commit(lfs, &newcwd, NULL, 0); }
// if (err) { }
// return err;
// } return 0;
// } }
//
// return 0;
//}
//int lfs_getattrs(lfs_t *lfs, const char *path, //int lfs_getattrs(lfs_t *lfs, const char *path,
// const struct lfs_attr *attrs, int count) { // const struct lfs_attr *attrs, int count) {
@@ -3940,9 +3975,9 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
.block_size = lfs->cfg->block_size, .block_size = lfs->cfg->block_size,
.block_count = lfs->cfg->block_count, .block_count = lfs->cfg->block_count,
.inline_size = lfs->cfg->inline_size, .inline_size = lfs->inline_size,
.attrs_size = lfs->cfg->attrs_size, .attrs_size = lfs->attrs_size,
.name_size = lfs->cfg->name_size, .name_size = lfs->name_size,
}; };
dir.count += 1; dir.count += 1;
@@ -4088,7 +4123,6 @@ int lfs_fs_traverse(lfs_t *lfs,
return err; return err;
} }
} }
} }
} }
@@ -4240,6 +4274,7 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t pair[2],
return err; return err;
} }
// TODO make this O(n) by using fetchwith to match the pointers
for (uint16_t id = 0; id < parent->count; id++) { for (uint16_t id = 0; id < parent->count; id++) {
int err = lfs_dir_getentry(lfs, parent, 0x43dff000, int err = lfs_dir_getentry(lfs, parent, 0x43dff000,
lfs_mktag(LFS_STRUCT_DIR, id, 0), entry); lfs_mktag(LFS_STRUCT_DIR, id, 0), entry);
@@ -4295,25 +4330,40 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
return false; return false;
} }
*/ */
static int lfs_moved(lfs_t *lfs, const lfs_block_t pair[2]) { static int lfs_moved(lfs_t *lfs, lfs_dir_t *fromdir, uint16_t fromid) {
// grab entry pair we're looking for
fromdir->moveid = -1;
lfs_entry_t fromentry;
int err = lfs_dir_getentry(lfs, fromdir, 0x43dff000,
lfs_mktag(LFS_STRUCT_DIR, fromid, 0), &fromentry);
fromdir->moveid = fromid;
if (err) {
return err;
}
// skip superblock // skip superblock
lfs_dir_t dir; lfs_dir_t todir;
int err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); err = lfs_dir_fetch(lfs, &todir, (const lfs_block_t[2]){0, 1});
if (err) { if (err) {
return err; return err;
} }
// iterate over all directory directory entries // iterate over all directory directory entries
while (!lfs_pairisnull(dir.tail)) { while (!lfs_pairisnull(todir.tail)) {
int err = lfs_dir_fetch(lfs, &dir, dir.tail); int err = lfs_dir_fetch(lfs, &todir, todir.tail);
if (err) { if (err) {
return err; return err;
} }
for (int id = 0; id < dir.count; id++) { for (int toid = 0; toid < todir.count; toid++) {
lfs_entry_t entry; if (lfs_paircmp(todir.pair, fromdir->pair) == 0 &&
int err = lfs_dir_getentry(lfs, &dir, 0x43dff000, toid == fromid) {
lfs_mktag(LFS_STRUCT_DIR, id, 0), &entry); continue;
}
lfs_entry_t toentry;
int err = lfs_dir_getentry(lfs, &todir, 0x43dff000,
lfs_mktag(LFS_STRUCT_DIR, toid, 0), &toentry);
if (err) { if (err) {
if (err == LFS_ERR_NOENT) { if (err == LFS_ERR_NOENT) {
continue; continue;
@@ -4321,16 +4371,7 @@ static int lfs_moved(lfs_t *lfs, const lfs_block_t pair[2]) {
return err; return err;
} }
err = lfs_dir_get(lfs, &dir, 0x7ffff000, &(lfs_entry_t){ if (lfs_paircmp(toentry.u.pair, fromentry.u.pair) == 0) {
lfs_mktag(LFS_TYPE_MOVE, id, 0)});
if (err != LFS_ERR_NOENT) {
if (!err) {
continue;
}
return err;
}
if (lfs_paircmp(entry.u.pair, pair) == 0) {
return true; return true;
} }
} }

6
lfs.h
View File

@@ -114,6 +114,11 @@ enum lfs_type {
LFS_STRUCT_INLINE = 0x000, LFS_STRUCT_INLINE = 0x000,
LFS_STRUCT_CTZ = 0x004, LFS_STRUCT_CTZ = 0x004,
LFS_STRUCT_DIR = 0x008, LFS_STRUCT_DIR = 0x008,
// internal sources
LFS_FROM_REGION = 0x000,
LFS_FROM_DISK = 0x001,
LFS_FROM_MOVE = 0x002,
}; };
// File open flags // File open flags
@@ -313,6 +318,7 @@ typedef struct lfs_dir {
uint16_t count; uint16_t count;
bool erased; bool erased;
bool split; bool split;
bool stop_at_commit; // TODO hmmm
int16_t moveid; int16_t moveid;
uint16_t id; uint16_t id;

View File

@@ -117,8 +117,6 @@ tests/test.py << TEST
for (int i = 0; i < $LARGESIZE; i++) { for (int i = 0; i < $LARGESIZE; i++) {
sprintf((char*)buffer, "test%d", i); sprintf((char*)buffer, "test%d", i);
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
printf("nameee %s\n", info.name);
printf("expect %s\n", (char*)buffer);
strcmp(info.name, (char*)buffer) => 0; strcmp(info.name, (char*)buffer) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
} }
@@ -154,6 +152,8 @@ tests/test.py << TEST
strcmp(info.name, "..") => 0; strcmp(info.name, "..") => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;
printf("nameee \"%s\"\n", info.name);
printf("expect \"%s\"\n", "burito");
strcmp(info.name, "burito") => 0; strcmp(info.name, "burito") => 0;
info.type => LFS_TYPE_REG; info.type => LFS_TYPE_REG;
lfs_dir_read(&lfs, &dir[0], &info) => 1; lfs_dir_read(&lfs, &dir[0], &info) => 1;