|
|
@@ -753,8 +753,7 @@ static int lfs_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
|
|
}
|
|
|
|
|
|
// internal dir operations
|
|
|
-static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
|
|
|
- bool split, const lfs_block_t tail[2]) {
|
|
|
+static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
|
|
|
// allocate pair of dir blocks (backwards, so we write to block 1 first)
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]);
|
|
|
@@ -775,16 +774,205 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
|
|
|
dir->off = sizeof(dir->rev);
|
|
|
dir->etag = 0;
|
|
|
dir->count = 0;
|
|
|
- dir->tail[0] = tail[0];
|
|
|
- dir->tail[1] = tail[1];
|
|
|
+ dir->tail[0] = 0xffffffff;
|
|
|
+ dir->tail[1] = 0xffffffff;
|
|
|
dir->erased = false;
|
|
|
- dir->split = split;
|
|
|
+ dir->split = false;
|
|
|
lfs_globalzero(&dir->locals);
|
|
|
|
|
|
// don't write out yet, let caller take care of that
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
+ lfs_mdir_t *dir, const lfs_block_t pair[2],
|
|
|
+ uint32_t findmask, uint32_t findtag,
|
|
|
+ const void *findbuffer) {
|
|
|
+ dir->pair[0] = pair[0];
|
|
|
+ dir->pair[1] = pair[1];
|
|
|
+ int32_t foundtag = LFS_ERR_NOENT;
|
|
|
+
|
|
|
+ // find the block with the most recent revision
|
|
|
+ uint32_t rev[2];
|
|
|
+ for (int i = 0; i < 2; i++) {
|
|
|
+ int err = lfs_bd_read(lfs, dir->pair[i], 0, &rev[i], sizeof(rev[i]));
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ rev[i] = lfs_fromle32(rev[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lfs_scmp(rev[1], rev[0]) > 0) {
|
|
|
+ lfs_pairswap(dir->pair);
|
|
|
+ lfs_pairswap(rev);
|
|
|
+ }
|
|
|
+
|
|
|
+ // load blocks and check crc
|
|
|
+ for (int i = 0; i < 2; i++) {
|
|
|
+ lfs_off_t off = sizeof(dir->rev);
|
|
|
+ uint32_t ptag = 0;
|
|
|
+ uint32_t crc = 0xffffffff;
|
|
|
+
|
|
|
+ dir->rev = lfs_tole32(rev[0]);
|
|
|
+ lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
|
|
|
+ dir->rev = lfs_fromle32(dir->rev);
|
|
|
+ dir->off = 0;
|
|
|
+
|
|
|
+ uint32_t tempfoundtag = foundtag;
|
|
|
+ uint16_t tempcount = 0;
|
|
|
+ lfs_block_t temptail[2] = {0xffffffff, 0xffffffff};
|
|
|
+ bool tempsplit = false;
|
|
|
+ lfs_global_t templocals;
|
|
|
+ lfs_globalzero(&templocals);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ // extract next tag
|
|
|
+ uint32_t tag;
|
|
|
+ int err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
+ off, &tag, sizeof(tag));
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ lfs_crc(&crc, &tag, sizeof(tag));
|
|
|
+ tag = lfs_fromle32(tag) ^ ptag;
|
|
|
+
|
|
|
+ // next commit not yet programmed
|
|
|
+ if (lfs_tagtype(ptag) == LFS_TYPE_CRC && !lfs_tagisvalid(tag)) {
|
|
|
+ dir->erased = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // check we're in valid range
|
|
|
+ if (off + sizeof(tag)+lfs_tagsize(tag) > lfs->cfg->block_size) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lfs_tagtype(tag) == LFS_TYPE_CRC) {
|
|
|
+ // check the crc attr
|
|
|
+ uint32_t dcrc;
|
|
|
+ int err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
+ off+sizeof(tag), &dcrc, sizeof(dcrc));
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ dcrc = lfs_fromle32(dcrc);
|
|
|
+
|
|
|
+ if (crc != dcrc) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ foundtag = tempfoundtag;
|
|
|
+ dir->off = off + sizeof(tag)+lfs_tagsize(tag);
|
|
|
+ dir->etag = tag;
|
|
|
+ dir->count = tempcount;
|
|
|
+ dir->tail[0] = temptail[0];
|
|
|
+ dir->tail[1] = temptail[1];
|
|
|
+ dir->split = tempsplit;
|
|
|
+ dir->locals = templocals;
|
|
|
+ crc = 0xffffffff;
|
|
|
+ } else {
|
|
|
+ err = lfs_bd_crc(lfs, dir->pair[0],
|
|
|
+ off+sizeof(tag), lfs_tagsize(tag), &crc);
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lfs_tagid(tag) < 0x3ff && lfs_tagid(tag) >= tempcount) {
|
|
|
+ tempcount = lfs_tagid(tag)+1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lfs_tagsubtype(tag) == LFS_TYPE_TAIL) {
|
|
|
+ tempsplit = (lfs_tagtype(tag) & 1);
|
|
|
+ err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
+ temptail, sizeof(temptail));
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ lfs_pairfromle32(temptail);
|
|
|
+ } else if (lfs_tagsubtype(tag) == LFS_TYPE_GLOBALS) {
|
|
|
+ err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
+ &templocals, sizeof(templocals));
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ } else if (lfs_tagsubtype(tag) == LFS_TYPE_DELETE) {
|
|
|
+ LFS_ASSERT(tempcount > 0);
|
|
|
+ tempcount -= 1;
|
|
|
+
|
|
|
+ if (lfs_tagid(tag) == lfs_tagid(tempfoundtag)) {
|
|
|
+ tempfoundtag = LFS_ERR_NOENT;
|
|
|
+ } else if (lfs_tagisvalid(tempfoundtag) &&
|
|
|
+ lfs_tagid(tag) < lfs_tagid(tempfoundtag)) {
|
|
|
+ tempfoundtag -= LFS_MKTAG(0, 1, 0);
|
|
|
+ }
|
|
|
+ } else if ((tag & findmask) == (findtag & findmask)) {
|
|
|
+ int res = lfs_bd_cmp(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
+ findbuffer, lfs_tagsize(tag));
|
|
|
+ if (res < 0) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res) {
|
|
|
+ // found a match
|
|
|
+ tempfoundtag = tag;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ptag = tag;
|
|
|
+ off += sizeof(tag)+lfs_tagsize(tag);
|
|
|
+ }
|
|
|
+
|
|
|
+ // consider what we have good enough
|
|
|
+ if (dir->off > 0) {
|
|
|
+ // synthetic move
|
|
|
+ if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) {
|
|
|
+ if (lfs_globalmoveid(lfs) == lfs_tagid(foundtag)) {
|
|
|
+ foundtag = LFS_ERR_NOENT;
|
|
|
+ } else if (lfs_tagisvalid(foundtag) &&
|
|
|
+ lfs_globalmoveid(lfs) < lfs_tagid(foundtag)) {
|
|
|
+ foundtag -= LFS_MKTAG(0, 1, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return foundtag;
|
|
|
+ }
|
|
|
+
|
|
|
+ // failed, try the other crc?
|
|
|
+ lfs_pairswap(dir->pair);
|
|
|
+ lfs_pairswap(rev);
|
|
|
+ }
|
|
|
+
|
|
|
+ LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]);
|
|
|
+ return LFS_ERR_CORRUPT;
|
|
|
+}
|
|
|
+
|
|
|
+static int lfs_dir_fetch(lfs_t *lfs,
|
|
|
+ lfs_mdir_t *dir, const lfs_block_t pair[2]) {
|
|
|
+ int32_t res = lfs_dir_find(lfs, dir, pair, 0xffffffff, 0xffffffff, NULL);
|
|
|
+ if (res < 0 && res != LFS_ERR_NOENT) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
|
|
|
+ uint32_t getmask, uint32_t gettag, void *buffer) {
|
|
|
+ int32_t getdiff = 0;
|
|
|
+ if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0 &&
|
|
|
+ lfs_tagid(gettag) <= lfs_globalmoveid(lfs)) {
|
|
|
+ // synthetic moves
|
|
|
+ getdiff = LFS_MKTAG(0, 1, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ return lfs_commitget(lfs, dir->pair[0], dir->off, dir->etag,
|
|
|
+ getmask, gettag, getdiff, buffer, false);
|
|
|
+}
|
|
|
+
|
|
|
static int lfs_dir_compact(lfs_t *lfs,
|
|
|
lfs_mdir_t *dir, const lfs_mattr_t *attrs,
|
|
|
lfs_mdir_t *source, uint16_t begin, uint16_t end) {
|
|
|
@@ -913,11 +1101,15 @@ split:
|
|
|
}
|
|
|
|
|
|
lfs_mdir_t tail;
|
|
|
- int err = lfs_dir_alloc(lfs, &tail, dir->split, dir->tail);
|
|
|
+ int err = lfs_dir_alloc(lfs, &tail);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ tail.split = dir->split;
|
|
|
+ tail.tail[0] = dir->tail[0];
|
|
|
+ tail.tail[1] = dir->tail[1];
|
|
|
+
|
|
|
err = lfs_dir_compact(lfs, &tail, attrs, dir, ack+1, end);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
@@ -966,18 +1158,6 @@ relocate:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // update any dirs/files that are affected
|
|
|
- for (int i = 0; i < 2; i++) {
|
|
|
- for (lfs_file_t *f = ((lfs_file_t**)&lfs->files)[i]; f; f = f->next) {
|
|
|
- if (lfs_paircmp(f->pair, dir->pair) == 0 &&
|
|
|
- f->id >= begin && f->id < end) {
|
|
|
- f->pair[0] = dir->pair[0];
|
|
|
- f->pair[1] = dir->pair[1];
|
|
|
- f->id -= begin;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -1110,218 +1290,33 @@ compact:
|
|
|
lfs_globalxor(&lfs->globals, &canceldiff);
|
|
|
|
|
|
// update any directories that are affected
|
|
|
- for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
|
|
|
+ for (lfs_mlist_t *d = lfs->mlist; d; d = d->next) {
|
|
|
if (lfs_paircmp(d->m.pair, dir->pair) == 0) {
|
|
|
d->m = *dir;
|
|
|
- if (d->id > lfs_tagid(deletetag)) {
|
|
|
- d->pos -= 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for (int i = 0; i < 2; i++) {
|
|
|
- for (lfs_file_t *f = ((lfs_file_t**)&lfs->files)[i]; f; f = f->next) {
|
|
|
- if (f->id == lfs_tagid(deletetag)) {
|
|
|
- f->pair[0] = 0xffffffff;
|
|
|
- f->pair[1] = 0xffffffff;
|
|
|
- } else if (f->id > lfs_tagid(deletetag)) {
|
|
|
- f->id -= 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
- lfs_mdir_t *dir, const lfs_block_t pair[2],
|
|
|
- uint32_t findmask, uint32_t findtag,
|
|
|
- const void *findbuffer) {
|
|
|
- dir->pair[0] = pair[0];
|
|
|
- dir->pair[1] = pair[1];
|
|
|
- int32_t foundtag = LFS_ERR_NOENT;
|
|
|
-
|
|
|
- // find the block with the most recent revision
|
|
|
- uint32_t rev[2];
|
|
|
- for (int i = 0; i < 2; i++) {
|
|
|
- int err = lfs_bd_read(lfs, dir->pair[i], 0, &rev[i], sizeof(rev[i]));
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
- rev[i] = lfs_fromle32(rev[i]);
|
|
|
- }
|
|
|
-
|
|
|
- if (lfs_scmp(rev[1], rev[0]) > 0) {
|
|
|
- lfs_pairswap(dir->pair);
|
|
|
- lfs_pairswap(rev);
|
|
|
- }
|
|
|
-
|
|
|
- // load blocks and check crc
|
|
|
- for (int i = 0; i < 2; i++) {
|
|
|
- lfs_off_t off = sizeof(dir->rev);
|
|
|
- uint32_t ptag = 0;
|
|
|
- uint32_t crc = 0xffffffff;
|
|
|
-
|
|
|
- dir->rev = lfs_tole32(rev[0]);
|
|
|
- lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
|
|
|
- dir->rev = lfs_fromle32(dir->rev);
|
|
|
- dir->off = 0;
|
|
|
-
|
|
|
- uint32_t tempfoundtag = foundtag;
|
|
|
- uint16_t tempcount = 0;
|
|
|
- lfs_block_t temptail[2] = {0xffffffff, 0xffffffff};
|
|
|
- bool tempsplit = false;
|
|
|
- lfs_global_t templocals;
|
|
|
- lfs_globalzero(&templocals);
|
|
|
-
|
|
|
- while (true) {
|
|
|
- // extract next tag
|
|
|
- uint32_t tag;
|
|
|
- int err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
- off, &tag, sizeof(tag));
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- lfs_crc(&crc, &tag, sizeof(tag));
|
|
|
- tag = lfs_fromle32(tag) ^ ptag;
|
|
|
-
|
|
|
- // next commit not yet programmed
|
|
|
- if (lfs_tagtype(ptag) == LFS_TYPE_CRC && !lfs_tagisvalid(tag)) {
|
|
|
- dir->erased = true;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // check we're in valid range
|
|
|
- if (off + sizeof(tag)+lfs_tagsize(tag) > lfs->cfg->block_size) {
|
|
|
- dir->erased = false;
|
|
|
- break;
|
|
|
+ if (d->id == lfs_tagid(deletetag)) {
|
|
|
+ d->m.pair[0] = 0xffffffff;
|
|
|
+ d->m.pair[1] = 0xffffffff;
|
|
|
+ } else if (d->id > lfs_tagid(deletetag)) {
|
|
|
+ d->id -= 1;
|
|
|
+ if (d->type == LFS_TYPE_DIR) {
|
|
|
+ ((lfs_dir_t*)d)->pos -= 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (lfs_tagtype(tag) == LFS_TYPE_CRC) {
|
|
|
- // check the crc attr
|
|
|
- uint32_t dcrc;
|
|
|
- int err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
- off+sizeof(tag), &dcrc, sizeof(dcrc));
|
|
|
+ while (d->id >= d->m.count && d->m.split) {
|
|
|
+ // we split and id is on tail now
|
|
|
+ d->id -= d->m.count;
|
|
|
+ int err = lfs_dir_fetch(lfs, &d->m, d->m.tail);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
- dcrc = lfs_fromle32(dcrc);
|
|
|
-
|
|
|
- if (crc != dcrc) {
|
|
|
- dir->erased = false;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- foundtag = tempfoundtag;
|
|
|
- dir->off = off + sizeof(tag)+lfs_tagsize(tag);
|
|
|
- dir->etag = tag;
|
|
|
- dir->count = tempcount;
|
|
|
- dir->tail[0] = temptail[0];
|
|
|
- dir->tail[1] = temptail[1];
|
|
|
- dir->split = tempsplit;
|
|
|
- dir->locals = templocals;
|
|
|
- crc = 0xffffffff;
|
|
|
- } else {
|
|
|
- err = lfs_bd_crc(lfs, dir->pair[0],
|
|
|
- off+sizeof(tag), lfs_tagsize(tag), &crc);
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- if (lfs_tagid(tag) < 0x3ff && lfs_tagid(tag) >= tempcount) {
|
|
|
- tempcount = lfs_tagid(tag)+1;
|
|
|
- }
|
|
|
-
|
|
|
- if (lfs_tagsubtype(tag) == LFS_TYPE_TAIL) {
|
|
|
- tempsplit = (lfs_tagtype(tag) & 1);
|
|
|
- err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
- temptail, sizeof(temptail));
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
- lfs_pairfromle32(temptail);
|
|
|
- } else if (lfs_tagsubtype(tag) == LFS_TYPE_GLOBALS) {
|
|
|
- err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
- &templocals, sizeof(templocals));
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
- } else if (lfs_tagsubtype(tag) == LFS_TYPE_DELETE) {
|
|
|
- LFS_ASSERT(tempcount > 0);
|
|
|
- tempcount -= 1;
|
|
|
-
|
|
|
- if (lfs_tagid(tag) == lfs_tagid(tempfoundtag)) {
|
|
|
- tempfoundtag = LFS_ERR_NOENT;
|
|
|
- } else if (lfs_tagisvalid(tempfoundtag) &&
|
|
|
- lfs_tagid(tag) < lfs_tagid(tempfoundtag)) {
|
|
|
- tempfoundtag -= LFS_MKTAG(0, 1, 0);
|
|
|
- }
|
|
|
- } else if ((tag & findmask) == (findtag & findmask)) {
|
|
|
- int res = lfs_bd_cmp(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
- findbuffer, lfs_tagsize(tag));
|
|
|
- if (res < 0) {
|
|
|
- return res;
|
|
|
- }
|
|
|
-
|
|
|
- if (res) {
|
|
|
- // found a match
|
|
|
- tempfoundtag = tag;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
-
|
|
|
- ptag = tag;
|
|
|
- off += sizeof(tag)+lfs_tagsize(tag);
|
|
|
}
|
|
|
-
|
|
|
- // consider what we have good enough
|
|
|
- if (dir->off > 0) {
|
|
|
- // synthetic move
|
|
|
- if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) {
|
|
|
- if (lfs_globalmoveid(lfs) == lfs_tagid(foundtag)) {
|
|
|
- foundtag = LFS_ERR_NOENT;
|
|
|
- } else if (lfs_tagisvalid(foundtag) &&
|
|
|
- lfs_globalmoveid(lfs) < lfs_tagid(foundtag)) {
|
|
|
- foundtag -= LFS_MKTAG(0, 1, 0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return foundtag;
|
|
|
- }
|
|
|
-
|
|
|
- // failed, try the other crc?
|
|
|
- lfs_pairswap(dir->pair);
|
|
|
- lfs_pairswap(rev);
|
|
|
- }
|
|
|
-
|
|
|
- LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]);
|
|
|
- return LFS_ERR_CORRUPT;
|
|
|
-}
|
|
|
-
|
|
|
-static int lfs_dir_fetch(lfs_t *lfs,
|
|
|
- lfs_mdir_t *dir, const lfs_block_t pair[2]) {
|
|
|
- int32_t res = lfs_dir_find(lfs, dir, pair, 0xffffffff, 0xffffffff, NULL);
|
|
|
- if (res < 0 && res != LFS_ERR_NOENT) {
|
|
|
- return res;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
|
|
|
- uint32_t getmask, uint32_t gettag, void *buffer) {
|
|
|
- int32_t getdiff = 0;
|
|
|
- if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0 &&
|
|
|
- lfs_tagid(gettag) <= lfs_globalmoveid(lfs)) {
|
|
|
- // synthetic moves
|
|
|
- getdiff = LFS_MKTAG(0, 1, 0);
|
|
|
- }
|
|
|
-
|
|
|
- return lfs_commitget(lfs, dir->pair[0], dir->off, dir->etag,
|
|
|
- getmask, gettag, getdiff, buffer, false);
|
|
|
-}
|
|
|
-
|
|
|
static int32_t lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, const char **path) {
|
|
|
// we reduce path to a single name if we can find it
|
|
|
const char *name = *path;
|
|
|
@@ -1478,11 +1473,13 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
|
|
|
lfs_alloc_ack(lfs);
|
|
|
|
|
|
lfs_mdir_t dir;
|
|
|
- err = lfs_dir_alloc(lfs, &dir, false, cwd.tail);
|
|
|
+ err = lfs_dir_alloc(lfs, &dir);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ dir.tail[0] = cwd.tail[0];
|
|
|
+ dir.tail[1] = cwd.tail[1];
|
|
|
err = lfs_dir_commit(lfs, &dir, NULL);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
@@ -1543,18 +1540,19 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
|
|
|
dir->id = 0;
|
|
|
dir->pos = 0;
|
|
|
|
|
|
- // add to list of directories
|
|
|
- dir->next = lfs->dirs;
|
|
|
- lfs->dirs = dir;
|
|
|
+ // add to list of mdirs
|
|
|
+ dir->type = LFS_TYPE_DIR;
|
|
|
+ dir->next = (lfs_dir_t*)lfs->mlist;
|
|
|
+ lfs->mlist = (lfs_mlist_t*)dir;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
|
|
|
- // remove from list of directories
|
|
|
- for (lfs_dir_t **p = &lfs->dirs; *p; p = &(*p)->next) {
|
|
|
- if (*p == dir) {
|
|
|
- *p = dir->next;
|
|
|
+ // remove from list of mdirs
|
|
|
+ for (lfs_mlist_t **p = &lfs->mlist; *p; p = &(*p)->next) {
|
|
|
+ if (*p == (lfs_mlist_t*)dir) {
|
|
|
+ *p = (*p)->next;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -1857,84 +1855,87 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // setup simple file details
|
|
|
+ int err = 0;
|
|
|
+ file->cfg = cfg;
|
|
|
+ file->flags = flags;
|
|
|
+ file->pos = 0;
|
|
|
+ file->cache.buffer = NULL;
|
|
|
+
|
|
|
// allocate entry for file if it doesn't exist
|
|
|
- lfs_mdir_t cwd;
|
|
|
- int32_t tag = lfs_dir_lookup(lfs, &cwd, &path);
|
|
|
+ int32_t tag = lfs_dir_lookup(lfs, &file->m, &path);
|
|
|
if (tag < 0 && !(tag == LFS_ERR_NOENT && path)) {
|
|
|
- return tag;
|
|
|
+ err = tag;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
+ // get id, add to list of mdirs to catch update changes
|
|
|
+ file->id = lfs_tagid(tag);
|
|
|
+ file->type = LFS_TYPE_REG;
|
|
|
+ file->next = (lfs_file_t*)lfs->mlist;
|
|
|
+ lfs->mlist = (lfs_mlist_t*)file;
|
|
|
+
|
|
|
if (tag == LFS_ERR_NOENT) {
|
|
|
if (!(flags & LFS_O_CREAT)) {
|
|
|
- return LFS_ERR_NOENT;
|
|
|
+ err = LFS_ERR_NOENT;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
// check that name fits
|
|
|
lfs_size_t nlen = strlen(path);
|
|
|
if (nlen > lfs->name_size) {
|
|
|
- return LFS_ERR_NAMETOOLONG;
|
|
|
+ err = LFS_ERR_NAMETOOLONG;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
// get next slot and create entry to remember name
|
|
|
- // TODO do we need to make file registered to list to catch updates from this commit? ie if id/cwd change
|
|
|
- uint16_t id = cwd.count;
|
|
|
- int err = lfs_dir_commit(lfs, &cwd,
|
|
|
- LFS_MKATTR(LFS_TYPE_REG, id, path, nlen,
|
|
|
- LFS_MKATTR(LFS_TYPE_INLINESTRUCT, id, NULL, 0,
|
|
|
+ file->id = file->m.count;
|
|
|
+ int err = lfs_dir_commit(lfs, &file->m,
|
|
|
+ LFS_MKATTR(LFS_TYPE_REG, file->id, path, nlen,
|
|
|
+ LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id, NULL, 0,
|
|
|
NULL)));
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- // TODO should we be catching this here?
|
|
|
- if (id >= cwd.count) {
|
|
|
- // catch updates from a compact in the above commit
|
|
|
- id -= cwd.count;
|
|
|
- cwd.pair[0] = cwd.tail[0];
|
|
|
- cwd.pair[1] = cwd.tail[1];
|
|
|
+ err = LFS_ERR_NAMETOOLONG;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
- tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, id, 0);
|
|
|
+ tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0);
|
|
|
} else if (flags & LFS_O_EXCL) {
|
|
|
- return LFS_ERR_EXIST;
|
|
|
+ err = LFS_ERR_EXIST;
|
|
|
+ goto cleanup;
|
|
|
} else if (lfs_tagtype(tag) != LFS_TYPE_REG) {
|
|
|
- return LFS_ERR_ISDIR;
|
|
|
+ err = LFS_ERR_ISDIR;
|
|
|
+ goto cleanup;
|
|
|
} else if (flags & LFS_O_TRUNC) {
|
|
|
// truncate if requested
|
|
|
- tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, lfs_tagid(tag), 0);
|
|
|
- flags |= LFS_F_DIRTY;
|
|
|
+ tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0);
|
|
|
+ file->flags |= LFS_F_DIRTY;
|
|
|
} else {
|
|
|
// try to load what's on disk, if it's inlined we'll fix it later
|
|
|
- tag = lfs_dir_get(lfs, &cwd, 0x7c3ff000,
|
|
|
- LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tagid(tag), 8), &file->ctz);
|
|
|
+ tag = lfs_dir_get(lfs, &file->m, 0x7c3ff000,
|
|
|
+ LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
|
|
|
if (tag < 0) {
|
|
|
- return tag;
|
|
|
+ err = tag;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
lfs_ctzfromle32(&file->ctz);
|
|
|
}
|
|
|
|
|
|
- // setup file struct
|
|
|
- file->cfg = cfg;
|
|
|
- file->pair[0] = cwd.pair[0];
|
|
|
- file->pair[1] = cwd.pair[1];
|
|
|
- file->id = lfs_tagid(tag);
|
|
|
- file->flags = flags;
|
|
|
- file->pos = 0;
|
|
|
-
|
|
|
// fetch attrs
|
|
|
for (const struct lfs_attr *a = file->cfg->attrs; a; a = a->next) {
|
|
|
if ((file->flags & 3) != LFS_O_WRONLY) {
|
|
|
- // TODO what if cwd is invalid from above compact?
|
|
|
- int32_t res = lfs_dir_get(lfs, &cwd, 0x7ffff000,
|
|
|
+ int32_t res = lfs_dir_get(lfs, &file->m, 0x7ffff000,
|
|
|
LFS_MKTAG(0x100 | a->type, file->id, a->size), a->buffer);
|
|
|
if (res < 0 && res != LFS_ERR_NOENT) {
|
|
|
- return res;
|
|
|
+ err = res;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if ((file->flags & 3) != LFS_O_RDONLY) {
|
|
|
if (a->size > lfs->attr_size) {
|
|
|
- return LFS_ERR_NOSPC;
|
|
|
+ err = LFS_ERR_NOSPC;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
file->flags |= LFS_F_DIRTY;
|
|
|
@@ -1946,14 +1947,17 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|
|
if (file->cfg->buffer) {
|
|
|
file->cache.buffer = file->cfg->buffer;
|
|
|
} else if ((file->flags & 3) == LFS_O_RDONLY) {
|
|
|
+ // TODO cache_size
|
|
|
file->cache.buffer = lfs_malloc(lfs->cfg->read_size);
|
|
|
if (!file->cache.buffer) {
|
|
|
- return LFS_ERR_NOMEM;
|
|
|
+ err = LFS_ERR_NOMEM;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
} else {
|
|
|
file->cache.buffer = lfs_malloc(lfs->cfg->prog_size);
|
|
|
if (!file->cache.buffer) {
|
|
|
- return LFS_ERR_NOMEM;
|
|
|
+ err = LFS_ERR_NOMEM;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1967,21 +1971,23 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|
|
|
|
|
// don't always read (may be new/trunc file)
|
|
|
if (file->ctz.size > 0) {
|
|
|
- int32_t res = lfs_dir_get(lfs, &cwd, 0x7c3ff000,
|
|
|
- LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tagid(tag), file->ctz.size),
|
|
|
+ int32_t res = lfs_dir_get(lfs, &file->m, 0x7c3ff000,
|
|
|
+ LFS_MKTAG(LFS_TYPE_STRUCT, file->id, file->ctz.size),
|
|
|
file->cache.buffer);
|
|
|
if (res < 0) {
|
|
|
- lfs_free(file->cache.buffer);
|
|
|
- return res;
|
|
|
+ err = res;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // add to list of files
|
|
|
- file->next = lfs->files;
|
|
|
- lfs->files = file;
|
|
|
-
|
|
|
return 0;
|
|
|
+
|
|
|
+cleanup:
|
|
|
+ // clean up lingering resources
|
|
|
+ file->flags |= LFS_F_ERRED;
|
|
|
+ lfs_file_close(lfs, file);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
|
|
|
@@ -1993,10 +1999,10 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
|
|
|
int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
|
|
|
int err = lfs_file_sync(lfs, file);
|
|
|
|
|
|
- // remove from list of files
|
|
|
- for (lfs_file_t **p = &lfs->files; *p; p = &(*p)->next) {
|
|
|
- if (*p == file) {
|
|
|
- *p = file->next;
|
|
|
+ // remove from list of mdirs
|
|
|
+ for (lfs_mlist_t **p = &lfs->mlist; *p; p = &(*p)->next) {
|
|
|
+ if (*p == (lfs_mlist_t*)file) {
|
|
|
+ *p = (*p)->next;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -2143,16 +2149,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
|
|
|
|
|
if ((file->flags & LFS_F_DIRTY) &&
|
|
|
!(file->flags & LFS_F_ERRED) &&
|
|
|
- !lfs_pairisnull(file->pair)) {
|
|
|
+ !lfs_pairisnull(file->m.pair)) {
|
|
|
// update dir entry
|
|
|
- // TODO keep list of dirs including these guys for no
|
|
|
- // need of another reload?
|
|
|
- lfs_mdir_t cwd;
|
|
|
- err = lfs_dir_fetch(lfs, &cwd, file->pair);
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
uint16_t type;
|
|
|
const void *buffer;
|
|
|
lfs_size_t size;
|
|
|
@@ -2170,7 +2168,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
|
|
|
|
|
// commit file data and attributes
|
|
|
lfs_ctztole32(&file->ctz);
|
|
|
- int err = lfs_dir_commit(lfs, &cwd,
|
|
|
+ int err = lfs_dir_commit(lfs, &file->m,
|
|
|
LFS_MKATTR(type, file->id, buffer, size,
|
|
|
LFS_MKATTR(LFS_FROM_ATTRS, file->id, file->cfg->attrs, 0,
|
|
|
NULL)));
|
|
|
@@ -2815,8 +2813,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
// setup default state
|
|
|
lfs->root[0] = 0xffffffff;
|
|
|
lfs->root[1] = 0xffffffff;
|
|
|
- lfs->files = NULL;
|
|
|
- lfs->dirs = NULL;
|
|
|
+ lfs->mlist = NULL;
|
|
|
lfs_globalones(&lfs->globals);
|
|
|
lfs_globalzero(&lfs->locals);
|
|
|
|
|
|
@@ -2855,16 +2852,14 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
|
|
|
// create superblock dir
|
|
|
lfs_mdir_t dir;
|
|
|
- err = lfs_dir_alloc(lfs, &dir, false,
|
|
|
- (const lfs_block_t[2]){0xffffffff, 0xffffffff});
|
|
|
+ err = lfs_dir_alloc(lfs, &dir);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
// write root directory
|
|
|
lfs_mdir_t root;
|
|
|
- err = lfs_dir_alloc(lfs, &root, false,
|
|
|
- (const lfs_block_t[2]){0xffffffff, 0xffffffff});
|
|
|
+ err = lfs_dir_alloc(lfs, &root);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -3054,7 +3049,11 @@ int lfs_fs_traverse(lfs_t *lfs,
|
|
|
}
|
|
|
|
|
|
// iterate over any open files
|
|
|
- for (lfs_file_t *f = lfs->files; f; f = f->next) {
|
|
|
+ for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
|
|
|
+ if (f->type != LFS_TYPE_REG) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
if ((f->flags & LFS_F_DIRTY) && !(f->flags & LFS_F_INLINE)) {
|
|
|
int err = lfs_ctztraverse(lfs, &lfs->rcache, &f->cache,
|
|
|
f->ctz.head, f->ctz.size, cb, data);
|
|
|
@@ -3128,6 +3127,21 @@ static int32_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
|
|
|
|
|
static int lfs_fs_relocate(lfs_t *lfs,
|
|
|
const lfs_block_t oldpair[2], lfs_block_t newpair[2]) {
|
|
|
+ // update internal root
|
|
|
+ if (lfs_paircmp(oldpair, lfs->root) == 0) {
|
|
|
+ LFS_DEBUG("Relocating root %d %d", newpair[0], newpair[1]);
|
|
|
+ lfs->root[0] = newpair[0];
|
|
|
+ lfs->root[1] = newpair[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // update internally tracked dirs
|
|
|
+ for (lfs_mlist_t *d = lfs->mlist; d; d = d->next) {
|
|
|
+ if (lfs_paircmp(oldpair, d->m.pair) == 0) {
|
|
|
+ d->m.pair[0] = newpair[0];
|
|
|
+ d->m.pair[1] = newpair[1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// find parent
|
|
|
lfs_mdir_t parent;
|
|
|
int32_t tag = lfs_fs_parent(lfs, oldpair, &parent);
|
|
|
@@ -3145,13 +3159,6 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- // update internal root
|
|
|
- if (lfs_paircmp(oldpair, lfs->root) == 0) {
|
|
|
- LFS_DEBUG("Relocating root %d %d", newpair[0], newpair[1]);
|
|
|
- lfs->root[0] = newpair[0];
|
|
|
- lfs->root[1] = newpair[1];
|
|
|
- }
|
|
|
-
|
|
|
// clean up bad block, which should now be a desync
|
|
|
return lfs_fs_forceconsistency(lfs);
|
|
|
}
|