diff --git a/lfs.c b/lfs.c index 497551ef..34e6f4f3 100644 --- a/lfs.c +++ b/lfs.c @@ -3152,14 +3152,23 @@ static int lfsr_rbyd_dnamelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd, lfs_size_t did, const char *name, lfs_size_t name_size, lfs_ssize_t *id_, lfsr_tag_t *tag_, lfs_size_t *weight_, lfsr_data_t *data_) { + // if we have an empty mdir, default to id = -1 + if (id_) { + *id_ = -1; + } + if (tag_) { + *tag_ = 0; + } + if (weight_) { + *weight_ = 0; + } + if (data_) { + *data_ = LFSR_DATA_NULL; + } + // binary search for our name lfs_ssize_t lower = 0; lfs_ssize_t upper = rbyd->weight; - // if we have an empty mdir, default to id = 0 - if (id_) { - *id_ = 0; - } - while (lower < upper) { lfsr_tag_t tag__; lfs_ssize_t id__; @@ -3198,7 +3207,16 @@ static int lfsr_rbyd_dnamelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd, // keep track of best-matching id >= our target if (id_) { - *id_ = id__ + weight__; + *id_ = id__; + } + if (tag_) { + *tag_ = tag__; + } + if (weight_) { + *weight_ = weight__; + } + if (data_) { + *data_ = data__; } } else { @@ -5686,9 +5704,19 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_ssize_t *rid, static int lfsr_mdir_dnamelookup(lfs_t *lfs, const lfsr_mdir_t *mdir, lfs_size_t did, const char *name, lfs_size_t name_size, lfs_ssize_t *id_, lfsr_tag_t *tag_, lfsr_data_t *data_) { - return lfsr_rbyd_dnamelookup(lfs, &mdir->rbyd, + int err = lfsr_rbyd_dnamelookup(lfs, &mdir->rbyd, did, name, name_size, id_, tag_, NULL, data_); + + // When not found, lfsr_rbyd_dnamelookup returns the id smaller than our + // expected name. This is correct for btree lookups, but not correct for + // mdir insertions. For mdirs we need to adjust this by 1 so we insert + // _after_ the smaller id. + if (id_ && err == LFS_ERR_NOENT) { + *id_ += 1; + } + + return err; } // note if we fail, we at least leave mdir_/rid_ with the best place to insert diff --git a/tests/t3_mtree.toml b/tests/t3_mtree.toml index 1b24f9c9..3c8ec639 100644 --- a/tests/t3_mtree.toml +++ b/tests/t3_mtree.toml @@ -145,6 +145,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -217,6 +220,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -288,6 +294,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -387,6 +396,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create entries lfsr_mdir_t mdir; @@ -399,7 +411,7 @@ code = ''' mdir.rbyd.off = cfg->block_size; lfs.mroot.rbyd.off = cfg->block_size; } - + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( LFSR_ATTR(rid, INLINED, +1, &alphas[i % 26], 1))) => 0; @@ -481,6 +493,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -586,6 +601,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -653,6 +671,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -723,6 +744,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -780,6 +804,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an mdir that needs to be split uint8_t buffer[SIZE]; @@ -845,6 +872,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an mdir that needs to be split uint8_t buffer[SIZE]; @@ -910,6 +940,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an mdir that needs to be split uint8_t buffer[SIZE]; @@ -958,6 +991,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1050,6 +1086,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1142,6 +1181,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1221,6 +1263,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create entries lfsr_mdir_t mdir; @@ -1317,6 +1362,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; for (lfs_size_t cycle = 0; cycle < CYCLES; cycle++) { // create entries @@ -1412,6 +1460,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -1542,6 +1593,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -1635,6 +1689,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -1727,6 +1784,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -1819,6 +1879,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1876,6 +1939,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1932,6 +1998,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1997,6 +2066,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -2101,6 +2173,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -2212,6 +2287,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -2292,6 +2370,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // force mroot to compact once, so the second compact below will trigger // a relocation @@ -2378,6 +2459,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // force mroot to compact once, so the second compact below will trigger // a relocation @@ -2475,6 +2559,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -2613,6 +2700,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2658,6 +2748,10 @@ code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; + lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2698,6 +2792,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2740,6 +2837,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2810,6 +2910,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2880,6 +2983,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -2974,6 +3080,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -3036,6 +3145,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -3125,6 +3237,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // insert a new entry, this should update our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( @@ -3222,6 +3337,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -3352,6 +3470,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; @@ -3484,6 +3605,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -3595,6 +3719,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // create entries lfsr_mdir_t mdir; @@ -3607,7 +3734,7 @@ code = ''' mdir.rbyd.off = cfg->block_size; lfs.mroot.rbyd.off = cfg->block_size; } - + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( LFSR_ATTR(rid, INLINED, +1, &alphas[i % 26], 1))) => 0; @@ -3746,6 +3873,9 @@ code = ''' lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; diff --git a/tests/t4_alloc.toml b/tests/t4_alloc.toml index 2d18cd93..18c0acc1 100644 --- a/tests/t4_alloc.toml +++ b/tests/t4_alloc.toml @@ -102,6 +102,10 @@ code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; + lfs_alloc_ack(&lfs); + // remove root dstart for now + lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( + LFSR_ATTR(0, UNR, -1, NULL, 0))) => 0; lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, lfsr_mtree_weight(&lfs)-1, &mdir) => 0; diff --git a/tests/t5_dirs.toml b/tests/t5_dirs.toml index 9db61ac9..93dc0a03 100644 --- a/tests/t5_dirs.toml +++ b/tests/t5_dirs.toml @@ -27,6 +27,37 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +# test that creating the same directory twice errors +[cases.t5_dirs_mkdir_exists] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make a directory + lfsr_mkdir(&lfs, "ardvark") => 0; + + // make the same directory, should error + lfsr_mkdir(&lfs, "ardvark") => LFS_ERR_EXIST; + + // cand check that this didn't interfere with our original directory + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_unmount(&lfs) => 0; +''' + [cases.t5_dirs_mkdir_siblings] code = ''' lfs_t lfs; @@ -73,7 +104,7 @@ code = ''' lfsr_mkdir(&lfs, "ardvark/batman") => 0; lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe") => 0; - // check that our mkdir worked + // check that our mkdirs worked lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; @@ -115,6 +146,314 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +[cases.t5_dirs_mkdir_many] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + + // check that our mkdir worked + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.t5_dirs_mkdir_many_2layers] +defines.N = [1, 2, 4, 8, 16, 32] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_mkdir(&lfs, name) => 0; + + // containing this many directories + for (lfs_size_t j = 0; j < N; j++) { + sprintf(name, "dir%04d/child%04d", i, j); + lfsr_mkdir(&lfs, name) => 0; + } + } + + // check that our mkdirs worked + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_open(&lfs, &dir, name) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t j = 0; j < N; j++) { + char name[256]; + sprintf(name, "child%04d", j); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + } + + lfsr_unmount(&lfs) => 0; +''' + +[cases.t5_dirs_mkdir_many_3layers] +defines.N = [1, 2, 4, 8] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_mkdir(&lfs, name) => 0; + + // containing this many directories + for (lfs_size_t j = 0; j < N; j++) { + sprintf(name, "dir%04d/child%04d", i, j); + lfsr_mkdir(&lfs, name) => 0; + + // containing this many directories + for (lfs_size_t k = 0; k < N; k++) { + sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); + lfsr_mkdir(&lfs, name) => 0; + } + } + } + + // check that our mkdirs worked + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_open(&lfs, &dir, name) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t j = 0; j < N; j++) { + char name[256]; + sprintf(name, "child%04d", j); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + for (lfs_size_t j = 0; j < N; j++) { + char name[256]; + sprintf(name, "dir%04d/child%04d", i, j); + lfsr_dir_open(&lfs, &dir, name) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t k = 0; k < N; k++) { + char name[256]; + sprintf(name, "grandchild%04d", k); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + } + } + + lfsr_unmount(&lfs) => 0; +''' + +[cases.t5_dirs_mkdir_many_linkedlist] +defines.N = [1, 2, 4, 8, 16, 32, 64] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // create this many directory in a sort of linked-list by nesting + char name[4096]; + memset(name, 0, sizeof(name)); + for (lfs_size_t i = 0; i < N; i++) { + sprintf(&name[strlen(name)], "/dir%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + + // check that our mkdir worked + memset(name, 0, sizeof(name)); + for (lfs_size_t i = 0; i < N; i++) { + sprintf(&name[strlen(name)], "/dir%04d", i); + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, name) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + if (i < N-1) { + char name2[256]; + sprintf(name2, "dir%04d", i+1); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name2) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + } + + lfsr_unmount(&lfs) => 0; +''' + +[cases.t5_dirs_mkdir_fuzz] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.SAMPLES = 10 +# -1 => all pseudo-random seeds +# n => reproduce a specific seed +defines.SEED = -1 +code = ''' + // iterate through severals seeds that we can reproduce easily + for (uint32_t seed = (SEED == -1 ? 1 : SEED); + (SEED == -1 ? seed < SAMPLES+1 : seed == SEED); + seed++) { + printf("--- seed: %d ---\n", seed); + // reset lfs here each iteration + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // set up a simulation to compare against + lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); + lfs_size_t sim_size = 0; + + uint32_t prng = seed; + for (lfs_size_t i = 0; i < N; i++) { + // choose a pseudo-random number, truncate to 4 decimals + lfs_size_t x = TEST_PRNG(&prng) % 1000; + + // insert into our sim + for (lfs_size_t j = 0;; j++) { + if (j >= sim_size || sim[j] >= x) { + // already seen? skip + if (sim[j] == x) { + goto next; + } + + // insert + memmove(&sim[j+1], &sim[j], + (sim_size-j)*sizeof(lfs_size_t)); + sim_size += 1; + sim[j] = x; + break; + } + } + + // create a directory here + char name[256]; + sprintf(name, "dir%04d", x); + lfsr_mkdir(&lfs, name) => 0; + next:; + } + + // test that our directories match our simulation + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t j = 0; j < sim_size; j++) { + char name[256]; + sprintf(name, "dir%04d", sim[j]); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + // clean up sim/lfs + free(sim); + lfsr_unmount(&lfs) => 0; + } +''' + +# TODO +# [cases.t5_dirs_did_collisions] +# [cases.t5_dirs_did_zero] +# [cases.t5_dirs_did_ones] +# [cases.t5_dirs_did_leb128_alignment] +