Skip to content

Commit d9367e0

Browse files
committed
Fixed collection of multiblock directories
Moslty just a hole in testing. Dir blocks were not being correctly collected when removing entries from very large files due to forgetting about the tail-bit in the directory block size. The test hole has now been filled. Also added lfs_entry_size to avoid having to repeat that expression since it is a bit ridiculous
1 parent a83b2fe commit d9367e0

File tree

2 files changed

+49
-14
lines changed

2 files changed

+49
-14
lines changed

lfs.c

+16-13
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ static inline bool lfs_pairsync(
346346
(paira[0] == pairb[1] && paira[1] == pairb[0]);
347347
}
348348

349+
static inline lfs_size_t lfs_entry_size(const lfs_entry_t *entry) {
350+
return 4 + entry->d.elen + entry->d.alen + entry->d.nlen;
351+
}
352+
349353
static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) {
350354
// allocate pair of dir blocks
351355
for (int i = 0; i < 2; i++) {
@@ -571,8 +575,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
571575
lfs_entry_t *entry, const void *data) {
572576
// check if we fit, if top bit is set we do not and move on
573577
while (true) {
574-
if (dir->d.size + 4+entry->d.elen+entry->d.alen+entry->d.nlen
575-
<= lfs->cfg->block_size) {
578+
if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size) {
576579
entry->off = dir->d.size - 4;
577580
return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
578581
{entry->off, 0, &entry->d, sizeof(entry->d)},
@@ -614,7 +617,8 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
614617

615618
static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
616619
// either shift out the one entry or remove the whole dir block
617-
if (dir->d.size == sizeof(dir->d)+4) {
620+
if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4
621+
+ lfs_entry_size(entry)) {
618622
lfs_dir_t pdir;
619623
int res = lfs_pred(lfs, dir->pair, &pdir);
620624
if (res < 0) {
@@ -623,18 +627,17 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
623627

624628
if (!(pdir.d.size & 0x80000000)) {
625629
return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
626-
{entry->off, 4+entry->d.elen+entry->d.alen+entry->d.nlen,
627-
NULL, 0},
630+
{entry->off, lfs_entry_size(entry), NULL, 0},
628631
}, 1);
629632
} else {
633+
pdir.d.size &= dir->d.size | 0x7fffffff;
630634
pdir.d.tail[0] = dir->d.tail[0];
631635
pdir.d.tail[1] = dir->d.tail[1];
632-
return lfs_dir_commit(lfs, dir, NULL, 0);
636+
return lfs_dir_commit(lfs, &pdir, NULL, 0);
633637
}
634638
} else {
635639
return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
636-
{entry->off, 4+entry->d.elen+entry->d.alen+entry->d.nlen,
637-
NULL, 0},
640+
{entry->off, lfs_entry_size(entry), NULL, 0},
638641
}, 1);
639642
}
640643
}
@@ -662,8 +665,8 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
662665
}
663666

664667
entry->off = dir->off;
665-
dir->off += 4+entry->d.elen+entry->d.alen+entry->d.nlen;
666-
dir->pos += 4+entry->d.elen+entry->d.alen+entry->d.nlen;
668+
dir->off += lfs_entry_size(entry);
669+
dir->pos += lfs_entry_size(entry);
667670
return 0;
668671
}
669672

@@ -1635,7 +1638,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
16351638
f->pair[0] = 0xffffffff;
16361639
f->pair[1] = 0xffffffff;
16371640
} else if (f->poff > entry.off) {
1638-
f->poff -= 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
1641+
f->poff -= lfs_entry_size(&entry);
16391642
}
16401643
}
16411644
}
@@ -1739,7 +1742,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
17391742
f->pair[0] = 0xffffffff;
17401743
f->pair[1] = 0xffffffff;
17411744
} else if (f->poff > oldentry.off) {
1742-
f->poff -= 4+oldentry.d.elen+oldentry.d.alen+oldentry.d.nlen;
1745+
f->poff -= lfs_entry_size(&oldentry);
17431746
}
17441747
}
17451748
}
@@ -1974,7 +1977,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
19741977
return err;
19751978
}
19761979

1977-
dir.off += 4+entry.d.elen+entry.d.alen+entry.d.nlen;
1980+
dir.off += lfs_entry_size(&entry);
19781981
if ((0xf & entry.d.type) == (0xf & LFS_TYPE_REG)) {
19791982
int err = lfs_index_traverse(lfs, &lfs->rcache, NULL,
19801983
entry.d.u.file.head, entry.d.u.file.size, cb, data);

tests/test_dirs.sh

+33-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ tests/test.py << TEST
124124
TEST
125125

126126
echo "--- Directory remove ---"
127-
# TESTING HERE
128127
tests/test.py << TEST
129128
lfs_mount(&lfs, &cfg) => 0;
130129
lfs_remove(&lfs, "potato") => LFS_ERR_INVAL;
@@ -283,5 +282,38 @@ tests/test.py << TEST
283282
lfs_unmount(&lfs) => 0;
284283
TEST
285284

285+
echo "--- Multi-block remove ---"
286+
tests/test.py << TEST
287+
lfs_mount(&lfs, &cfg) => 0;
288+
lfs_remove(&lfs, "cactus") => LFS_ERR_INVAL;
289+
290+
for (int i = 0; i < $LARGESIZE; i++) {
291+
sprintf((char*)buffer, "cactus/test%d", i);
292+
lfs_remove(&lfs, (char*)buffer) => 0;
293+
}
294+
295+
lfs_remove(&lfs, "cactus") => 0;
296+
lfs_unmount(&lfs) => 0;
297+
TEST
298+
tests/test.py << TEST
299+
lfs_mount(&lfs, &cfg) => 0;
300+
lfs_dir_open(&lfs, &dir[0], "/") => 0;
301+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
302+
strcmp(info.name, ".") => 0;
303+
info.type => LFS_TYPE_DIR;
304+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
305+
strcmp(info.name, "..") => 0;
306+
info.type => LFS_TYPE_DIR;
307+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
308+
strcmp(info.name, "burito") => 0;
309+
info.type => LFS_TYPE_REG;
310+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
311+
strcmp(info.name, "coldpotato") => 0;
312+
info.type => LFS_TYPE_DIR;
313+
lfs_dir_read(&lfs, &dir[0], &info) => 0;
314+
lfs_dir_close(&lfs, &dir[0]) => 0;
315+
lfs_unmount(&lfs) => 0;
316+
TEST
317+
286318
echo "--- Results ---"
287319
tests/stats.py

0 commit comments

Comments
 (0)