WIP progress so far

This commit is contained in:
Christopher Haster
2018-05-27 10:15:28 -05:00
parent ca9e43158d
commit de0b719b56
3 changed files with 336 additions and 305 deletions

636
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,25 @@ 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;
if (lfs_tag_type(entry.tag) & 0x100) { return 0;
if (lfs_tag_type(entry.tag) == move->type) {
return 2;
}
} 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 +641,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 +719,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 +773,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;
@@ -901,9 +862,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 +1152,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 +1161,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 +1198,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 +1213,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 +1224,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 +1298,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 +1412,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 +2330,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 +3586,207 @@ 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
// err = lfs_dir_commit(lfs, &oldcwd, &(lfs_entrylist_t){
// // update pair if newcwd == oldcwd {lfs_mktag(LFS_TYPE_MOVE, oldid, 0)}});
// if (samepair) { if (err) {
// newcwd = oldcwd; return err;
// } }
//
// // move to new location if (samepair) {
// lfs_entry_t newentry = preventry; // update pair if newcwd == oldcwd
// newentry.d = oldentry.d; newcwd = oldcwd;
// newentry.d.type &= ~LFS_STRUCT_MOVED; }
// newentry.d.nlen = nlen;
// newentry.size = prevexists ? preventry.size : 0; // move to new location
// // TODO NAME?????
// lfs_size_t newsize = oldentry.size - oldentry.d.nlen + newentry.d.nlen; // TODO HAH, move doesn't want to override things (due
// err = lfs_dir_set(lfs, &newcwd, &newentry, (struct lfs_region[]){ // to its use in compaction), but that's _exactly_ what we want here
// {LFS_FROM_REGION, 0, prevexists ? preventry.size : 0, err = lfs_dir_commitwith(lfs, &newcwd, lfs_commit_move,
// &(struct lfs_region_region){ &(struct lfs_commit_move){.dir=&oldcwd, .id={oldid, newid}});
// oldcwd.pair[0], oldentry.off, (struct lfs_region[]){ if (err) {
// {LFS_FROM_MEM, 0, 4, &newentry.d, 4}, return err;
// {LFS_FROM_MEM, newsize-nlen, 0, newpath, nlen}}, 2}, }
// newsize}}, 1); // TODO NONONONONO
// if (err) { // TODO also don't call strlen twice (see prev name check)
// return err; err = lfs_dir_commit(lfs, &newcwd, &(lfs_entrylist_t){
// } {lfs_mktag(LFS_TYPE_NAME, newid, strlen(newpath)),
// .u.buffer=(void*)newpath}});
// // update pair if newcwd == oldcwd if (err) {
// if (samepair) { return err;
// oldcwd = newcwd; }
// }
// if (samepair) {
// // remove old entry // update pair if newcwd == oldcwd
// err = lfs_dir_set(lfs, &oldcwd, &oldentry, (struct lfs_region[]){ oldcwd = newcwd;
// {LFS_FROM_MEM, 0, oldentry.size, NULL, 0}}, 1); }
// if (err) {
// return err; // remove old entry
// } err = lfs_dir_delete(lfs, &oldcwd, oldid);
// if (err) {
// // if we were a directory, find pred, replace tail return err;
// if (prevexists && (0xf & preventry.d.type) == LFS_TYPE_DIR) { }
// int res = lfs_pred(lfs, dir.pair, &newcwd);
// if (res < 0) { // if we were a directory, find pred, replace tail
// return res; // TODO can this just deorphan?
// } if (prevexists && lfs_tag_subtype(preventry.tag) == LFS_TYPE_DIR) {
// err = lfs_deorphan(lfs);
// LFS_ASSERT(res); // must have pred if (err) {
// newcwd.d.tail[0] = dir.d.tail[0]; return err;
// newcwd.d.tail[1] = dir.d.tail[1]; }
// }
// err = lfs_dir_commit(lfs, &newcwd, NULL, 0);
// if (err) { return 0;
// return err; }
// }
// }
//
// 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 +3964,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 +4112,6 @@ int lfs_fs_traverse(lfs_t *lfs,
return err; return err;
} }
} }
} }
} }
@@ -4240,6 +4263,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 +4319,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 +4360,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;
} }
} }

1
lfs.h
View File

@@ -313,6 +313,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;