Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Haster <chaster@utexas.edu>2018-12-29 16:53:12 +0300
committerChristopher Haster <chaster@utexas.edu>2019-01-14 08:56:01 +0300
commitb989b4a89f6c69b0219b64404de89be63923ca44 (patch)
tree03a004da63667df2d3490704877647a3fd51cbfc
parenta548ce68c116cb2ac67c266e4a4b1aa9fb3f8e45 (diff)
Cleaned up tag encoding, now with clear chunk field
Before, the tag format's type field was limited to 9-bits. This sounds like a lot, but this field needed to encode up to 256 user-specified types. This limited the flexibility of the encoded types. As time went on, more bits in the type field were repurposed for various things, leaving a rather fragile type field. Here we make the jump to full 11-bit type fields. This comes at the cost of a smaller length field, however the use of the length field was always going to come with a RAM limitation. Rather than putting pressure on RAM for inline files, the new type field lets us encode a chunk number, splitting up inline files into multiple updatable units. This actually pushes the theoretical inline max from 8KiB to 256KiB! (Note that we only allow a single 1KiB chunk for now, chunky inline files is just a theoretical future improvement). Here is the new 32-bit tag format, note that there are multiple levels of types which break down into more info: [---- 32 ----] [1|-- 11 --|-- 10 --|-- 10 --] ^. ^ . ^ ^- entry length |. | . \------------ file id chunk info |. \-----.------------------ type info (type3) \.-----------.------------------ valid bit [-3-|-- 8 --] ^ ^- chunk info \------- type info (type1) Additionally, I've split the CREATE tag into separate SPLICE and NAME tags. This simplified the new compact logic a bit. For now, littlefs still follows the rule that a NAME tag precedes any other tags related to a file, but this can change in the future.
-rw-r--r--lfs.c733
-rw-r--r--lfs.h58
-rwxr-xr-xtests/corrupt.py2
-rwxr-xr-xtests/debug.py54
-rwxr-xr-xtests/test_alloc.sh6
-rwxr-xr-xtests/test_format.sh3
6 files changed, 411 insertions, 445 deletions
diff --git a/lfs.c b/lfs.c
index b4d5d52..3d3aea0 100644
--- a/lfs.c
+++ b/lfs.c
@@ -112,6 +112,12 @@ static int lfs_bd_read(lfs_t *lfs,
return 0;
}
+enum {
+ LFS_CMP_EQ = 0,
+ LFS_CMP_LT = 1,
+ LFS_CMP_GT = 2,
+};
+
static int lfs_bd_cmp(lfs_t *lfs,
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
lfs_block_t block, lfs_off_t off,
@@ -128,11 +134,11 @@ static int lfs_bd_cmp(lfs_t *lfs,
}
if (dat != data[i]) {
- return (dat < data[i]) ? 1 : 2;
+ return (dat < data[i]) ? LFS_CMP_LT : LFS_CMP_GT;
}
}
- return 0;
+ return LFS_CMP_EQ;
}
static int lfs_bd_flush(lfs_t *lfs,
@@ -152,8 +158,12 @@ static int lfs_bd_flush(lfs_t *lfs,
int res = lfs_bd_cmp(lfs,
NULL, rcache, diff,
pcache->block, pcache->off, pcache->buffer, diff);
- if (res) {
- return (res < 0) ? res : LFS_ERR_CORRUPT;
+ if (res < 0) {
+ return res;
+ }
+
+ if (res != LFS_CMP_EQ) {
+ return LFS_ERR_CORRUPT;
}
}
@@ -268,34 +278,38 @@ typedef uint32_t lfs_tag_t;
typedef int32_t lfs_stag_t;
#define LFS_MKTAG(type, id, size) \
- (((lfs_tag_t)(type) << 22) | ((lfs_tag_t)(id) << 13) | (lfs_tag_t)(size))
+ (((lfs_tag_t)(type) << 20) | ((lfs_tag_t)(id) << 10) | (lfs_tag_t)(size))
static inline bool lfs_tag_isvalid(lfs_tag_t tag) {
return !(tag & 0x80000000);
}
-static inline bool lfs_tag_isuser(lfs_tag_t tag) {
- return (tag & 0x40000000);
+static inline bool lfs_tag_isdelete(lfs_tag_t tag) {
+ return ((int32_t)(tag << 22) >> 22) == -1;
}
-static inline bool lfs_tag_isdelete(lfs_tag_t tag) {
- return ((int32_t)(tag << 19) >> 19) == -1;
+static inline uint16_t lfs_tag_type1(lfs_tag_t tag) {
+ return (tag & 0x70000000) >> 20;
+}
+
+static inline uint16_t lfs_tag_type3(lfs_tag_t tag) {
+ return (tag & 0x7ff00000) >> 20;
}
-static inline uint16_t lfs_tag_type(lfs_tag_t tag) {
- return (tag & 0x7fc00000) >> 22;
+static inline uint8_t lfs_tag_chunk(lfs_tag_t tag) {
+ return (tag & 0x0ff00000) >> 20;
}
-static inline uint16_t lfs_tag_subtype(lfs_tag_t tag) {
- return ((tag & 0x78000000) >> 26) << 4;
+static inline int8_t lfs_tag_splice(lfs_tag_t tag) {
+ return (int8_t)lfs_tag_chunk(tag);
}
static inline uint16_t lfs_tag_id(lfs_tag_t tag) {
- return (tag & 0x003fe000) >> 13;
+ return (tag & 0x000ffc00) >> 10;
}
static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) {
- return tag & 0x00001fff;
+ return tag & 0x000003ff;
}
static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) {
@@ -405,7 +419,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
const struct lfs_mattr *attrs);
static int lfs_dir_compact(lfs_t *lfs,
- lfs_mdir_t *dir, const struct lfs_mattr *attrs,
+ lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
lfs_mdir_t *source, uint16_t begin, uint16_t end);
static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2],
lfs_mdir_t *pdir);
@@ -481,114 +495,67 @@ static void lfs_alloc_ack(lfs_t *lfs) {
/// Metadata pair and directory operations ///
-static int lfs_dir_traverseget(lfs_t *lfs,
- const lfs_mdir_t *dir, const struct lfs_mattr *attrs,
- lfs_tag_t getmask, lfs_tag_t gettag, lfs_stag_t getdiff,
- int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
- lfs_block_t block = dir->pair[0];
+static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir,
+ lfs_tag_t gmask, lfs_tag_t gtag, void *buffer) {
lfs_off_t off = dir->off;
lfs_tag_t ntag = dir->etag;
- gettag += getdiff;
+ lfs_stag_t gdiff = 0;
+
+ if (lfs->globals.hasmove &&
+ lfs_pair_cmp(dir->pair, lfs->globals.pair) == 0 &&
+ lfs_tag_id(gtag) <= lfs->globals.id) {
+ // synthetic moves
+ gdiff -= LFS_MKTAG(0, 1, 0);
+ }
// iterate over dir block backwards (for faster lookups)
- while (attrs || off >= sizeof(lfs_tag_t) + lfs_tag_dsize(ntag)) {
- lfs_tag_t tag;
- const void *buffer;
- struct lfs_diskoff disk;
- if (attrs) {
- tag = attrs->tag;
- buffer = attrs->buffer;
- attrs = attrs->next;
- } else {
- off -= lfs_tag_dsize(ntag);
+ while (off >= sizeof(lfs_tag_t) + lfs_tag_dsize(ntag)) {
+ off -= lfs_tag_dsize(ntag);
+ lfs_tag_t tag = ntag;
+ int err = lfs_bd_read(lfs,
+ &lfs->pcache, &lfs->rcache, sizeof(ntag),
+ dir->pair[0], off, &ntag, sizeof(ntag));
+ if (err) {
+ return err;
+ }
- tag = ntag;
- buffer = &disk;
- disk.block = block;
- disk.off = off + sizeof(tag);
+ ntag = (lfs_frombe32(ntag) ^ tag) & 0x7fffffff;
- int err = lfs_bd_read(lfs,
- &lfs->pcache, &lfs->rcache, sizeof(ntag),
- block, off, &ntag, sizeof(ntag));
- if (err) {
- return err;
+ if (lfs_tag_id(gmask) != 0 &&
+ lfs_tag_type1(tag) == LFS_TYPE_SPLICE &&
+ lfs_tag_id(tag) <= lfs_tag_id(gtag - gdiff)) {
+ if (tag == (LFS_MKTAG(LFS_TYPE_CREATE, 0, 0) |
+ (LFS_MKTAG(0, 0x3ff, 0) & (gtag - gdiff)))) {
+ // found where we were created
+ return LFS_ERR_NOENT;
}
- ntag = lfs_frombe32(ntag) ^ tag;
- tag |= 0x80000000;
+ // move around splices
+ gdiff += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
}
- if (lfs_tag_id(getmask) != 0 &&
- lfs_tag_subtype(tag) == LFS_TYPE_DELETE) {
- // something was deleted, need to move around it
- if (lfs_tag_id(tag) <= lfs_tag_id(gettag - getdiff)) {
- getdiff -= LFS_MKTAG(0, 1, 0);
- }
- }
-
- if ((tag & getmask) == ((gettag - getdiff) & getmask)) {
+ if ((gmask & tag) == (gmask & (gtag - gdiff))) {
if (lfs_tag_isdelete(tag)) {
return LFS_ERR_NOENT;
}
- return cb(data, tag + getdiff, buffer);
- }
-
- if (lfs_tag_id(getmask) != 0 &&
- lfs_tag_subtype(tag) == LFS_TYPE_CREATE) {
- // found where something was created
- if (lfs_tag_id(tag) == lfs_tag_id(gettag - getdiff)) {
- break;
- } else if (lfs_tag_id(tag) <
- lfs_tag_id(gettag - getdiff)) {
- getdiff += LFS_MKTAG(0, 1, 0);
+ lfs_size_t diff = lfs_min(lfs_tag_size(tag),
+ lfs_tag_size(gtag));
+ err = lfs_bd_read(lfs,
+ &lfs->pcache, &lfs->rcache, diff,
+ dir->pair[0], off+sizeof(tag), buffer, diff);
+ if (err) {
+ return err;
}
- }
- }
-
- return LFS_ERR_NOENT;
-}
-struct lfs_dir_get_read {
- lfs_t *lfs;
- void *buffer;
- lfs_size_t size;
-};
+ memset((uint8_t*)buffer + diff, 0,
+ lfs_tag_size(gtag) - diff);
-static int lfs_dir_get_read(void *data,
- lfs_tag_t tag, const void *buffer) {
- struct lfs_dir_get_read *get = data;
- lfs_t *lfs = get->lfs;
- const struct lfs_diskoff *disk = buffer;
- if (get->buffer) {
- lfs_size_t diff = lfs_min(lfs_tag_size(tag), get->size);
- int err = lfs_bd_read(lfs,
- &lfs->pcache, &lfs->rcache, diff,
- disk->block, disk->off, get->buffer, diff);
- if (err) {
- return err;
+ return tag + gdiff;
}
-
- memset((uint8_t*)get->buffer + diff, 0, get->size - diff);
}
- return tag & 0x7fffffff;
-}
-
-static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir,
- lfs_tag_t getmask, lfs_tag_t gettag, void *buffer) {
- lfs_stag_t getdiff = 0;
- if (lfs->globals.hasmove &&
- lfs_pair_cmp(dir->pair, lfs->globals.pair) == 0 &&
- lfs_tag_id(gettag) <= lfs->globals.id) {
- // synthetic moves
- gettag += LFS_MKTAG(0, 1, 0);
- getdiff -= LFS_MKTAG(0, 1, 0);
- }
-
- return lfs_dir_traverseget(lfs, dir, NULL, getmask, gettag, getdiff,
- lfs_dir_get_read, &(struct lfs_dir_get_read){
- lfs, buffer, lfs_tag_size(gettag)});
+ return LFS_ERR_NOENT;
}
static int lfs_dir_traverse_filter(void *p,
@@ -597,46 +564,36 @@ static int lfs_dir_traverse_filter(void *p,
(void)buffer;
// check for redundancy
- lfs_tag_t mask = (lfs_tag_isuser(tag) ? 0x7fffe000 : 0x783fe000);
- if (!lfs_tag_subtype(tag) == LFS_TYPE_CREATE && (
- (mask & tag) == (mask & *filtertag) ||
- (lfs_tag_subtype(tag) == LFS_TYPE_DELETE &&
- lfs_tag_id(tag) == lfs_tag_id(*filtertag)))) {
+ uint32_t mask = LFS_MKTAG(0x7ff, 0x3ff, 0);
+ if ((mask & tag) == (mask & *filtertag) ||
+ (mask & tag) == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
+ (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) {
return true;
}
// check if we need to adjust for created/deleted tags
- if (lfs_tag_subtype(tag) == LFS_TYPE_CREATE &&
+ if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE &&
lfs_tag_id(tag) <= lfs_tag_id(*filtertag)) {
- *filtertag += LFS_MKTAG(0, 1, 0);
- } else if (lfs_tag_subtype(tag) == LFS_TYPE_DELETE &&
- lfs_tag_id(tag) < lfs_tag_id(*filtertag)) {
- *filtertag -= LFS_MKTAG(0, 1, 0);
+ *filtertag += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
}
return false;
}
-static int lfs_dir_traverseall(lfs_t *lfs, const lfs_mdir_t *dir,
- const struct lfs_mattr *attrs,
- lfs_off_t off, lfs_tag_t ptag, int i,
- uint16_t begin, uint16_t end, lfs_stag_t diff,
+static int lfs_dir_traverse(lfs_t *lfs,
+ const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag,
+ const struct lfs_mattr *attrs, int attrcount,
+ lfs_tag_t tmask, lfs_tag_t ttag,
+ uint16_t begin, uint16_t end, int16_t diff,
int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
- // precompute length of attrs so we can iterate backwards, this
- // lets us "append" commits
- int attrcount = 0;
- for (const struct lfs_mattr *a = attrs; a; a = a->next) {
- attrcount += 1;
- }
-
- // iterate over directory and attrs
- while (off+lfs_tag_dsize(ptag) < dir->off || i < attrcount) {
+ // iterate over directory and attrs, we iterate over attrs in reverse order
+ // which lets us "append" commits
+ while (off+lfs_tag_dsize(ptag) < dir->off || attrcount > 0) {
lfs_tag_t tag;
const void *buffer;
struct lfs_diskoff disk;
if (off+lfs_tag_dsize(ptag) < dir->off) {
off += lfs_tag_dsize(ptag);
-
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, sizeof(tag),
dir->pair[0], off, &tag, sizeof(tag));
@@ -651,27 +608,27 @@ static int lfs_dir_traverseall(lfs_t *lfs, const lfs_mdir_t *dir,
ptag = tag;
} else {
const struct lfs_mattr *a = attrs;
- for (int j = 0; j < attrcount-i-1; j++) {
+ for (int j = 0; j < attrcount-1; j++) {
a = a->next;
}
tag = a->tag;
buffer = a->buffer;
- i += 1;
+ attrcount -= 1;
+ }
+
+ lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0);
+ if ((mask & tmask & tag) != (mask & tmask & ttag)) {
+ continue;
}
// do we need to filter? inlining the filtering logic here allows
// for some minor optimizations
- if (end <= 0x1ff) {
- if (!lfs_tag_isuser(tag) &&
- lfs_tag_subtype(tag) != LFS_TYPE_STRUCT &&
- lfs_tag_subtype(tag) != LFS_TYPE_FROM) {
- continue;
- }
-
+ if (lfs_tag_id(tmask) != 0) {
// scan for duplicates and update tag based on creates/deletes
- int filter = lfs_dir_traverseall(lfs, dir, attrs,
- off, ptag, i, 0, -1, 0,
+ int filter = lfs_dir_traverse(lfs,
+ dir, off, ptag, attrs, attrcount,
+ 0, 0, 0, 0, 0,
lfs_dir_traverse_filter, &tag);
if (filter < 0) {
return filter;
@@ -688,27 +645,28 @@ static int lfs_dir_traverseall(lfs_t *lfs, const lfs_mdir_t *dir,
}
// handle special cases for mcu-side operations
- if (lfs_tag_type(tag) == LFS_FROM_MOVE) {
+ if (lfs_tag_type3(tag) == LFS_FROM_MOVE) {
uint16_t fromid = lfs_tag_size(tag);
uint16_t toid = lfs_tag_id(tag);
- int err = lfs_dir_traverseall(lfs, buffer, NULL,
- 0, 0xffffffff, 0, fromid, fromid+1,
- LFS_MKTAG(0, toid - fromid, 0) + diff,
+ int err = lfs_dir_traverse(lfs,
+ buffer, 0, 0xffffffff, NULL, 0,
+ LFS_MKTAG(0x600, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_STRUCT, 0, 0),
+ fromid, fromid+1, toid-fromid+diff,
cb, data);
if (err) {
return err;
}
- } else if (lfs_tag_type(tag) == LFS_FROM_USERATTRS) {
+ } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) {
for (const struct lfs_attr *a = buffer; a; a = a->next) {
- int err = cb(data,
- LFS_MKTAG(0x100 | a->type, lfs_tag_id(tag), a->size)
- + diff, a->buffer);
+ int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a->type,
+ lfs_tag_id(tag) + diff, a->size), a->buffer);
if (err) {
return err;
}
}
} else {
- int err = cb(data, tag + diff, buffer);
+ int err = cb(data, tag + LFS_MKTAG(0, diff, 0), buffer);
if (err) {
return err;
}
@@ -718,30 +676,14 @@ static int lfs_dir_traverseall(lfs_t *lfs, const lfs_mdir_t *dir,
return 0;
}
-static int lfs_dir_traverse(lfs_t *lfs, const lfs_mdir_t *dir,
- const struct lfs_mattr *attrs,
- uint16_t begin, uint16_t end, lfs_stag_t diff,
- int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
- // grab create tags first, this is needed because we can't really order
- // tags by ids otherwise, and our insertion cleverness becomes a problem
- for (uint16_t i = begin; i < end; i++) {
- int err = lfs_dir_traverseget(lfs, dir, attrs,
- 0x783fe000, LFS_MKTAG(LFS_TYPE_CREATE, i, 0),
- diff, cb, data);
- if (err) {
- return err;
- }
- }
-
- // then just grab every other tag in range, order is no longer a concern
- return lfs_dir_traverseall(lfs, dir, attrs,
- 0, 0xffffffff, 0, begin, end, diff, cb, data);
-}
-
static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
lfs_mdir_t *dir, const lfs_block_t pair[2],
- lfs_tag_t matchmask, lfs_tag_t matchtag,
+ lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id,
int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) {
+ // we can find tag very efficiently during a fetch, since we're already
+ // scanning the entire directory
+ lfs_stag_t besttag = -1;
+
// find the block with the most recent revision
uint32_t revs[2];
int r = 0;
@@ -759,41 +701,32 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
}
}
- // now fetch the actual dir (and find match)
- lfs_stag_t foundtag = 0;
- dir->pair[0] = pair[0];
- dir->pair[1] = pair[1];
- dir->off = 0;
- if (r != 0) {
- lfs_pair_swap(dir->pair);
- lfs_pair_swap(revs);
- }
+ dir->pair[0] = pair[(r+0)%2];
+ dir->pair[1] = pair[(r+1)%2];
+ dir->rev = revs[(r+0)%2];
+ dir->off = 0; // nonzero = found some commits
- // scan tags and check crcs
+ // now scan tags to fetch the actual dir and find possible match
for (int i = 0; i < 2; i++) {
- lfs_block_t block = dir->pair[0];
- lfs_off_t off = sizeof(uint32_t);
+ lfs_off_t off = 0;
lfs_tag_t ptag = 0xffffffff;
- lfs_tag_t tempfoundtag = foundtag;
- lfs_mdir_t temp = {
- .pair = {dir->pair[0], dir->pair[1]},
- .rev = revs[0],
- .tail = {0xffffffff, 0xffffffff},
- .split = false,
- .count = 0,
- };
+ uint16_t tempcount = 0;
+ lfs_block_t temptail[2] = {0xffffffff, 0xffffffff};
+ bool tempsplit = false;
+ lfs_stag_t tempbesttag = besttag;
- temp.rev = lfs_tole32(temp.rev);
- uint32_t crc = lfs_crc(0xffffffff, &temp.rev, sizeof(temp.rev));
- temp.rev = lfs_fromle32(temp.rev);
+ dir->rev = lfs_tole32(dir->rev);
+ uint32_t crc = lfs_crc(0xffffffff, &dir->rev, sizeof(dir->rev));
+ dir->rev = lfs_fromle32(dir->rev);
while (true) {
// extract next tag
lfs_tag_t tag;
+ off += lfs_tag_dsize(ptag);
int err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
- block, off, &tag, sizeof(tag));
+ dir->pair[0], off, &tag, sizeof(tag));
if (err) {
if (err == LFS_ERR_CORRUPT) {
// can't continue?
@@ -806,24 +739,21 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
crc = lfs_crc(crc, &tag, sizeof(tag));
tag = lfs_frombe32(tag) ^ ptag;
- // next commit not yet programmed
- if (!lfs_tag_isvalid(tag)) {
- dir->erased = (lfs_tag_subtype(ptag) == LFS_TYPE_CRC);
+ // next commit not yet programmed or we're not in valid range
+ if (!lfs_tag_isvalid(tag) ||
+ off + lfs_tag_dsize(tag) > lfs->cfg->block_size) {
+ dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC);
break;
}
- // check we're in valid range
- if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) {
- dir->erased = false;
- break;
- }
+ ptag = tag;
- if (lfs_tag_subtype(tag) == LFS_TYPE_CRC) {
+ if (lfs_tag_type1(tag) == LFS_TYPE_CRC) {
// check the crc attr
uint32_t dcrc;
err = lfs_bd_read(lfs,
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
- block, off+sizeof(tag), &dcrc, sizeof(dcrc));
+ dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc));
if (err) {
if (err == LFS_ERR_CORRUPT) {
dir->erased = false;
@@ -839,113 +769,127 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
}
// reset the next bit if we need to
- tag ^= (lfs_tag_type(tag) & 1) << 31;
+ ptag ^= (lfs_tag_chunk(tag) & 1) << 31;
+
+ // toss our crc into the filesystem seed for
+ // pseudorandom numbers
lfs->seed ^= crc;
- crc = 0xffffffff;
// update with what's found so far
- foundtag = tempfoundtag;
- *dir = temp;
+ besttag = tempbesttag;
dir->off = off + lfs_tag_dsize(tag);
- dir->etag = tag;
- } else {
- // crc the entry first, leaving it in the cache
- for (lfs_off_t j = sizeof(tag); j < lfs_tag_dsize(tag); j++) {
- uint8_t dat;
- err = lfs_bd_read(lfs,
- NULL, &lfs->rcache, lfs->cfg->block_size,
- block, off+j, &dat, 1);
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- dir->erased = false;
- break;
- }
- return err;
- }
+ dir->etag = ptag;
+ dir->count = tempcount;
+ dir->tail[0] = temptail[0];
+ dir->tail[1] = temptail[1];
+ dir->split = tempsplit;
- crc = lfs_crc(crc, &dat, 1);
- }
-
- // check for special tags
- if (lfs_tag_subtype(tag) == LFS_TYPE_CREATE) {
- temp.count += 1;
+ // reset crc
+ crc = 0xffffffff;
+ continue;
+ }
- if (tempfoundtag &&
- lfs_tag_id(tag) <= lfs_tag_id(tempfoundtag)) {
- tempfoundtag += LFS_MKTAG(0, 1, 0);
- }
- } else if (lfs_tag_subtype(tag) == LFS_TYPE_DELETE) {
- LFS_ASSERT(temp.count > 0);
- temp.count -= 1;
-
- if (tempfoundtag && !lfs_tag_isdelete(tempfoundtag) &&
- lfs_tag_id(tag) == lfs_tag_id(tempfoundtag)) {
- tempfoundtag = 0;
- } else if (tempfoundtag &&
- lfs_tag_id(tag) < lfs_tag_id(tempfoundtag)) {
- tempfoundtag -= LFS_MKTAG(0, 1, 0);
- }
- } else if (lfs_tag_subtype(tag) == LFS_TYPE_TAIL) {
- temp.split = (lfs_tag_type(tag) & 1);
- err = lfs_bd_read(lfs,
- &lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
- block, off+sizeof(tag),
- &temp.tail, sizeof(temp.tail));
- if (err) {
- if (err == LFS_ERR_CORRUPT) {
- dir->erased = false;
- break;
- }
+ // crc the entry first, hopefully leaving it in the cache
+ for (lfs_off_t j = sizeof(tag); j < lfs_tag_dsize(tag); j++) {
+ uint8_t dat;
+ err = lfs_bd_read(lfs,
+ NULL, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off+j, &dat, 1);
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ dir->erased = false;
+ break;
}
- lfs_pair_fromle32(temp.tail);
+ return err;
}
- if ((tag & matchmask) == (matchtag & matchmask)) {
- // found a match?
- if (lfs_tag_isdelete(tag)) {
- tempfoundtag = 0;
- } else if (cb) {
- int res = cb(data, tag, &(struct lfs_diskoff){
- block, off+sizeof(tag)});
- if (res < 0) {
- if (res == LFS_ERR_CORRUPT) {
- dir->erased = false;
- break;
- }
- return res;
- }
+ crc = lfs_crc(crc, &dat, 1);
+ }
- if (res && (!tempfoundtag ||
- lfs_tag_id(res) <= lfs_tag_id(tempfoundtag))) {
- tempfoundtag = res;
- }
+ // directory modification tags?
+ if (lfs_tag_type1(tag) == LFS_TYPE_NAME) {
+ // increase count of files if necessary
+ if (lfs_tag_id(tag) >= tempcount) {
+ tempcount = lfs_tag_id(tag) + 1;
+ }
+ } else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) {
+ tempcount += lfs_tag_splice(tag);
+
+ if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
+ (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) {
+ tempbesttag |= 0x80000000;
+ } else if (tempbesttag != -1 &&
+ lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
+ tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0);
+ }
+ } else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) {
+ tempsplit = (lfs_tag_chunk(tag) & 1);
+ err = lfs_bd_read(lfs,
+ &lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
+ dir->pair[0], off+sizeof(tag),
+ &temptail, sizeof(temptail));
+ if (err) {
+ if (err == LFS_ERR_CORRUPT) {
+ dir->erased = false;
+ break;
}
}
+ lfs_pair_fromle32(temptail);
}
- ptag = tag;
- off += lfs_tag_dsize(tag);
+ // found a match for our fetcher?
+ if ((fmask & tag) == (fmask & ftag)) {
+ int res = cb(data, tag, &(struct lfs_diskoff){
+ dir->pair[0], off+sizeof(tag)});
+ if (res < 0) {
+ if (res == LFS_ERR_CORRUPT) {
+ dir->erased = false;
+ break;
+ }
+ return res;
+ }
+
+ if (res == LFS_CMP_EQ) {
+ // found a match
+ tempbesttag = tag;
+ } else if (res == LFS_CMP_GT &&
+ lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) {
+ // found a greater match, keep track to keep things sorted
+ tempbesttag = tag | 0x80000000;
+ }
+ }
}
// consider what we have good enough
if (dir->off > 0) {
// synthetic move
- if (foundtag &&
- lfs->globals.hasmove &&
+ if (lfs->globals.hasmove &&
lfs_pair_cmp(dir->pair, lfs->globals.pair) == 0) {
- if (lfs->globals.id == lfs_tag_id(foundtag)) {
- foundtag = 0;
- } else if (lfs->globals.id < lfs_tag_id(foundtag)) {
- foundtag -= LFS_MKTAG(0, 1, 0);
+ if (lfs->globals.id == lfs_tag_id(besttag)) {
+ besttag |= 0x80000000;
+ } else if (besttag != -1 &&
+ lfs->globals.id < lfs_tag_id(besttag)) {
+ besttag -= LFS_MKTAG(0, 1, 0);
}
}
- return foundtag;
+ // found tag? or found best id?
+ if (id) {
+ *id = lfs_min(lfs_tag_id(besttag), dir->count);
+ }
+
+ if (lfs_tag_isvalid(besttag)) {
+ return besttag;
+ } else if (lfs_tag_id(besttag) < dir->count) {
+ return LFS_ERR_NOENT;
+ } else {
+ return 0;
+ }
}
- // failed, try the other crc?
+ // failed, try the other block?
lfs_pair_swap(dir->pair);
- lfs_pair_swap(revs);
+ dir->rev = revs[(r+1)%2];
}
LFS_ERROR("Corrupted dir pair at %"PRIu32" %"PRIu32,
@@ -955,22 +899,23 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
static int lfs_dir_fetch(lfs_t *lfs,
lfs_mdir_t *dir, const lfs_block_t pair[2]) {
- return lfs_dir_fetchmatch(lfs, dir, pair,
- 0xffffffff, 0x00000000, NULL, NULL);
+ // note, mask=-1, tag=0 can never match a tag since this
+ // pattern has the invalid bit set
+ return lfs_dir_fetchmatch(lfs, dir, pair, -1, 0, NULL, NULL, NULL);
}
static int lfs_dir_getglobals(lfs_t *lfs, const lfs_mdir_t *dir,
struct lfs_globals *globals) {
struct lfs_globals locals;
- lfs_stag_t res = lfs_dir_get(lfs, dir, 0x78000000,
+ lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0, 0),
LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals);
if (res < 0 && res != LFS_ERR_NOENT) {
return res;
}
if (res != LFS_ERR_NOENT) {
- locals.hasmove = (lfs_tag_type(res) & 2);
- locals.orphans = (lfs_tag_type(res) & 1);
+ locals.hasmove = (lfs_tag_type3(res) & 2);
+ locals.orphans = (lfs_tag_type3(res) & 1);
// xor together to find resulting globals
lfs_global_xor(globals, &locals);
}
@@ -980,32 +925,32 @@ static int lfs_dir_getglobals(lfs_t *lfs, const lfs_mdir_t *dir,
static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
uint16_t id, struct lfs_info *info) {
- if (id == 0x1ff) {
+ if (id == 0x3ff) {
// special case for root
strcpy(info->name, "/");
info->type = LFS_TYPE_DIR;
return 0;
}
- lfs_stag_t tag = lfs_dir_get(lfs, dir, 0x7c3fe000,
- LFS_MKTAG(LFS_TYPE_DIR, id, lfs->name_max+1), info->name);
+ lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name);
if (tag < 0) {
return tag;
}
- info->type = lfs_tag_type(tag);
+ info->type = lfs_tag_type3(tag);
struct lfs_ctz ctz;
- tag = lfs_dir_get(lfs, dir, 0x783fe000,
+ tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz);
if (tag < 0) {
return tag;
}
lfs_ctz_fromle32(&ctz);
- if (lfs_tag_type(tag) == LFS_TYPE_CTZSTRUCT) {
+ if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) {
info->size = ctz.size;
- } else if (lfs_tag_type(tag) == LFS_TYPE_INLINESTRUCT) {
+ } else if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) {
info->size = lfs_tag_size(tag);
}
@@ -1024,35 +969,34 @@ static int lfs_dir_find_match(void *data,
lfs_t *lfs = name->lfs;
const struct lfs_diskoff *disk = buffer;
+ // compare with disk
lfs_size_t diff = lfs_min(name->size, lfs_tag_size(tag));
int res = lfs_bd_cmp(lfs,
NULL, &lfs->rcache, diff,
disk->block, disk->off, name->name, diff);
- if (res < 0) {
+ if (res != LFS_CMP_EQ) {
return res;
}
- // found match?
- if (res == 0 && name->size == lfs_tag_size(tag)) {
- return tag;
+ // only equal if our size is still the same
+ if (name->size != lfs_tag_size(tag)) {
+ return (name->size < lfs_tag_size(tag)) ? LFS_CMP_LT : LFS_CMP_GT;
}
- // a greater name found, exit early
- if (res > 1 && lfs_tag_type(tag) != LFS_TYPE_SUPERBLOCK) {
- return tag | 0x1fff;
- }
-
- // no match keep looking
- return 0;
+ // found a match!
+ return LFS_CMP_EQ;
}
static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
const char **path, uint16_t *id) {
// we reduce path to a single name if we can find it
const char *name = *path;
+ if (id) {
+ *id = 0x3ff;
+ }
// default to root dir
- lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x1ff, 0);
+ lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0);
dir->tail[0] = lfs->root[0];
dir->tail[1] = lfs->root[1];
@@ -1102,13 +1046,13 @@ nextname:
*path = name;
// only continue if we hit a directory
- if (lfs_tag_type(tag) != LFS_TYPE_DIR) {
+ if (lfs_tag_type3(tag) != LFS_TYPE_DIR) {
return LFS_ERR_NOTDIR;
}
// grab the entry data
- if (lfs_tag_id(tag) != 0x1ff) {
- lfs_stag_t res = lfs_dir_get(lfs, dir, 0x783fe000,
+ if (lfs_tag_id(tag) != 0x3ff) {
+ lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), dir->tail);
if (res < 0) {
return res;
@@ -1119,30 +1063,21 @@ nextname:
// find entry matching name
while (true) {
tag = lfs_dir_fetchmatch(lfs, dir, dir->tail,
- 0x7c000000, LFS_MKTAG(LFS_TYPE_DIR, 0, namelen),
+ LFS_MKTAG(0x780, 0, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, 0, namelen),
+ // are we last name?
+ (strchr(name, '/') == NULL) ? id : NULL,
lfs_dir_find_match, &(struct lfs_dir_find_match){
lfs, name, namelen});
if (tag < 0) {
return tag;
}
- if (id) {
- if (strchr(name, '/') != NULL) {
- // if path is not only name we're not valid candidate
- // for creation
- *id = 0x1ff;
- } else if (tag) {
- *id = lfs_tag_id(tag);
- } else {
- *id = dir->count;
- }
- }
-
- if (tag && !lfs_tag_isdelete(tag)) {
+ if (tag) {
break;
}
- if (lfs_tag_isdelete(tag) || !dir->split) {
+ if (!dir->split) {
return LFS_ERR_NOENT;
}
}
@@ -1227,7 +1162,7 @@ static int lfs_dir_commitglobals(lfs_t *lfs, struct lfs_commit *commit,
struct lfs_globals *globals) {
return lfs_dir_commitattr(lfs, commit,
LFS_MKTAG(LFS_TYPE_GLOBALS + 2*globals->hasmove + globals->orphans,
- 0x1ff, 10), globals);
+ 0x3ff, 10), globals);
}
static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
@@ -1247,7 +1182,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
// build crc tag
bool reset = ~lfs_frombe32(tag) >> 31;
tag = LFS_MKTAG(LFS_TYPE_CRC + reset,
- 0x1ff, off - (commit->off+sizeof(lfs_tag_t)));
+ 0x3ff, off - (commit->off+sizeof(lfs_tag_t)));
// write out crc
uint32_t footer[2];
@@ -1347,12 +1282,12 @@ static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, const lfs_mdir_t *tail) {
// update pred's tail
return lfs_dir_commit(lfs, dir,
LFS_MKATTR(LFS_TYPE_TAIL + dir->split,
- 0x1ff, dir->tail, sizeof(dir->tail),
+ 0x3ff, dir->tail, sizeof(dir->tail),
NULL));
}
static int lfs_dir_split(lfs_t *lfs,
- lfs_mdir_t *dir, const struct lfs_mattr *attrs,
+ lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
lfs_mdir_t *source, uint16_t split, uint16_t end) {
// create tail directory
lfs_mdir_t tail;
@@ -1365,7 +1300,7 @@ static int lfs_dir_split(lfs_t *lfs,
tail.tail[0] = dir->tail[0];
tail.tail[1] = dir->tail[1];
- err = lfs_dir_compact(lfs, &tail, attrs, source, split, end);
+ err = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end);
if (err) {
return err;
}
@@ -1402,7 +1337,7 @@ static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) {
}
static int lfs_dir_compact(lfs_t *lfs,
- lfs_mdir_t *dir, const struct lfs_mattr *attrs,
+ lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
lfs_mdir_t *source, uint16_t begin, uint16_t end) {
// save some state in case block is bad
const lfs_block_t oldpair[2] = {dir->pair[1], dir->pair[0]};
@@ -1413,7 +1348,11 @@ static int lfs_dir_compact(lfs_t *lfs,
while (true) {
// find size
lfs_size_t size = 0;
- int err = lfs_dir_traverse(lfs, source, attrs, begin, end, 0,
+ int err = lfs_dir_traverse(lfs,
+ source, 0, 0xffffffff, attrs, attrcount,
+ LFS_MKTAG(0x400, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, 0, 0),
+ begin, end, -begin,
lfs_dir_commit_size, &size);
if (err) {
return err;
@@ -1431,7 +1370,8 @@ static int lfs_dir_compact(lfs_t *lfs,
// largest size that fits with a small binary search, but right now
// it's not worth the code size
uint16_t split = (end - begin) / 2;
- err = lfs_dir_split(lfs, dir, attrs, source, begin+split, end);
+ err = lfs_dir_split(lfs, dir, attrs, attrcount,
+ source, begin+split, end);
if (err) {
// if we fail to split, we may be able to overcompact, unless
// we're too big for even the full block, in which case our
@@ -1460,7 +1400,8 @@ static int lfs_dir_compact(lfs_t *lfs,
// by itself, so expand cautiously
if ((lfs_size_t)res < lfs->cfg->block_count/2) {
LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev);
- int err = lfs_dir_split(lfs, dir, attrs, source, begin, end);
+ int err = lfs_dir_split(lfs, dir, attrs, attrcount,
+ source, begin, end);
if (err && err != LFS_ERR_NOSPC) {
return err;
}
@@ -1522,9 +1463,12 @@ static int lfs_dir_compact(lfs_t *lfs,
return err;
}
- // commit with a move
- err = lfs_dir_traverse(lfs, source, attrs,
- begin, end, -LFS_MKTAG(0, begin, 0),
+ // traverse the directory, this time writing out all unique tags
+ err = lfs_dir_traverse(lfs,
+ source, 0, 0xffffffff, attrs, attrcount,
+ LFS_MKTAG(0x400, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_NAME, 0, 0),
+ begin, end, -begin,
lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){
lfs, &commit});
if (err) {
@@ -1553,7 +1497,7 @@ static int lfs_dir_compact(lfs_t *lfs,
lfs_pair_tole32(dir->tail);
err = lfs_dir_commitattr(lfs, &commit,
LFS_MKTAG(LFS_TYPE_TAIL + dir->split,
- 0x1ff, sizeof(dir->tail)), dir->tail);
+ 0x3ff, sizeof(dir->tail)), dir->tail);
lfs_pair_fromle32(dir->tail);
if (err) {
if (err == LFS_ERR_CORRUPT) {
@@ -1651,10 +1595,10 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
lfs_tag_t createtag = 0xffffffff;
int attrcount = 0;
for (const struct lfs_mattr *a = attrs; a; a = a->next) {
- if (lfs_tag_subtype(a->tag) == LFS_TYPE_CREATE) {
+ if (lfs_tag_type3(a->tag) == LFS_TYPE_CREATE) {
dir->count += 1;
createtag = a->tag;
- } else if (lfs_tag_subtype(a->tag) == LFS_TYPE_DELETE) {
+ } else if (lfs_tag_type3(a->tag) == LFS_TYPE_DELETE) {
LFS_ASSERT(dir->count > 0);
dir->count -= 1;
deletetag = a->tag;
@@ -1690,8 +1634,9 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
// traverse attrs that need to be written out
lfs_pair_tole32(dir->tail);
- int err = lfs_dir_traverseall(lfs, dir, attrs,
- dir->off, dir->etag, 0, 0, -1, 0,
+ int err = lfs_dir_traverse(lfs,
+ dir, dir->off, dir->etag, attrs, attrcount,
+ 0, 0, 0, 0, 0,
lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){
lfs, &commit});
lfs_pair_fromle32(dir->tail);
@@ -1740,7 +1685,8 @@ compact:
// fall back to compaction
lfs_cache_drop(lfs, &lfs->pcache);
- int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count);
+ int err = lfs_dir_compact(lfs, dir, attrs, attrcount,
+ dir, 0, dir->count);
if (err) {
return err;
}
@@ -1798,7 +1744,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
lfs_mdir_t cwd;
uint16_t id;
err = lfs_dir_find(lfs, &cwd, &path, &id);
- if (!(err == LFS_ERR_NOENT && id != 0x1ff)) {
+ if (!(err == LFS_ERR_NOENT && id != 0x3ff)) {
return (err < 0) ? err : LFS_ERR_EXIST;
}
@@ -1844,7 +1790,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
pred.tail[1] = dir.pair[1];
lfs_global_orphans(lfs, +1);
err = lfs_dir_commit(lfs, &pred,
- LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x1ff,
+ LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
pred.tail, sizeof(pred.tail),
NULL));
if (err) {
@@ -1858,10 +1804,11 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
err = lfs_dir_commit(lfs, &cwd,
LFS_MKATTR(LFS_TYPE_DIRSTRUCT, id, dir.pair, sizeof(dir.pair),
LFS_MKATTR(LFS_TYPE_DIR, id, path, nlen,
+ LFS_MKATTR(LFS_TYPE_CREATE, id, NULL, 0,
(!cwd.split)
- ? LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x1ff,
+ ? LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff,
cwd.tail, sizeof(cwd.tail), NULL)
- : NULL)));
+ : NULL))));
lfs_pair_fromle32(dir.pair);
if (err) {
return err;
@@ -1876,18 +1823,18 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
return tag;
}
- if (lfs_tag_type(tag) != LFS_TYPE_DIR) {
+ if (lfs_tag_type3(tag) != LFS_TYPE_DIR) {
return LFS_ERR_NOTDIR;
}
lfs_block_t pair[2];
- if (lfs_tag_id(tag) == 0x1ff) {
+ if (lfs_tag_id(tag) == 0x3ff) {
// handle root dir separately
pair[0] = lfs->root[0];
pair[1] = lfs->root[1];
} else {
// get dir pair from parent
- lfs_stag_t res = lfs_dir_get(lfs, &dir->m, 0x783fe000,
+ lfs_stag_t res = lfs_dir_get(lfs, &dir->m, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair);
if (res < 0) {
return res;
@@ -2238,7 +2185,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
// allocate entry for file if it doesn't exist
lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
- if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x1ff)) {
+ if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) {
err = tag;
goto cleanup;
}
@@ -2265,7 +2212,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
err = lfs_dir_commit(lfs, &file->m,
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id, NULL, 0,
LFS_MKATTR(LFS_TYPE_REG, file->id, path, nlen,
- NULL)));
+ LFS_MKATTR(LFS_TYPE_CREATE, file->id, NULL, 0,
+ NULL))));
if (err) {
err = LFS_ERR_NAMETOOLONG;
goto cleanup;
@@ -2275,7 +2223,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
} else if (flags & LFS_O_EXCL) {
err = LFS_ERR_EXIST;
goto cleanup;
- } else if (lfs_tag_type(tag) != LFS_TYPE_REG) {
+ } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) {
err = LFS_ERR_ISDIR;
goto cleanup;
} else if (flags & LFS_O_TRUNC) {
@@ -2284,7 +2232,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
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, &file->m, 0x783fe000,
+ tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
if (tag < 0) {
err = tag;
@@ -2296,8 +2244,10 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
// fetch attrs
for (const struct lfs_attr *a = file->cfg->attrs; a; a = a->next) {
if ((file->flags & 3) != LFS_O_WRONLY) {
- lfs_stag_t res = lfs_dir_get(lfs, &file->m, 0x7fffe000,
- LFS_MKTAG(0x100 | a->type, file->id, a->size), a->buffer);
+ lfs_stag_t res = lfs_dir_get(lfs, &file->m,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_USERATTR + a->type, file->id, a->size),
+ a->buffer);
if (res < 0 && res != LFS_ERR_NOENT) {
err = res;
goto cleanup;
@@ -2328,7 +2278,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
// zero to avoid information leak
lfs_cache_zero(lfs, &file->cache);
- if (lfs_tag_type(tag) == LFS_TYPE_INLINESTRUCT) {
+ if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) {
// load inline files
file->ctz.head = 0xfffffffe;
file->ctz.size = lfs_tag_size(tag);
@@ -2339,7 +2289,8 @@ 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) {
- lfs_stag_t res = lfs_dir_get(lfs, &file->m, 0x783fe000,
+ lfs_stag_t res = lfs_dir_get(lfs, &file->m,
+ LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, file->ctz.size),
file->cache.buffer);
if (res < 0) {
@@ -2896,10 +2847,10 @@ int lfs_remove(lfs_t *lfs, const char *path) {
}
lfs_mdir_t dir;
- if (lfs_tag_type(tag) == LFS_TYPE_DIR) {
+ if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
// must be empty before removal
lfs_block_t pair[2];
- lfs_stag_t res = lfs_dir_get(lfs, &cwd, 0x783fe000,
+ lfs_stag_t res = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair);
if (res < 0) {
return res;
@@ -2927,7 +2878,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
return err;
}
- if (lfs_tag_type(tag) == LFS_TYPE_DIR) {
+ if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
// fix orphan
lfs_global_orphans(lfs, -1);
@@ -2963,7 +2914,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
lfs_mdir_t newcwd;
uint16_t newid;
lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid);
- if (prevtag < 0 && !(prevtag == LFS_ERR_NOENT && newid != 0x1ff)) {
+ if (prevtag < 0 && !(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) {
return err;
}
@@ -2974,12 +2925,12 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
if (nlen > lfs->name_max) {
return LFS_ERR_NAMETOOLONG;
}
- } else if (lfs_tag_type(prevtag) != lfs_tag_type(oldtag)) {
+ } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) {
return LFS_ERR_ISDIR;
- } else if (lfs_tag_type(prevtag) == LFS_TYPE_DIR) {
+ } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
// must be empty before removal
lfs_block_t prevpair[2];
- lfs_stag_t res = lfs_dir_get(lfs, &newcwd, 0x783fe000,
+ lfs_stag_t res = lfs_dir_get(lfs, &newcwd, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair);
if (res < 0) {
return res;
@@ -3014,10 +2965,11 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// move over all attributes
err = lfs_dir_commit(lfs, &newcwd,
LFS_MKATTR(LFS_FROM_MOVE, newid, &oldcwd, lfs_tag_id(oldtag),
- LFS_MKATTR(lfs_tag_type(oldtag), newid, newpath, strlen(newpath),
+ LFS_MKATTR(lfs_tag_type3(oldtag), newid, newpath, strlen(newpath),
+ LFS_MKATTR(LFS_TYPE_CREATE, newid, NULL, 0,
(prevtag != LFS_ERR_NOENT)
? LFS_MKATTR(LFS_TYPE_DELETE, newid, NULL, 0, NULL)
- : NULL)));
+ : NULL))));
if (err) {
return err;
}
@@ -3031,7 +2983,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
}
}
- if (prevtag != LFS_ERR_NOENT && lfs_tag_type(prevtag) == LFS_TYPE_DIR) {
+ if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
// fix orphan
lfs_global_orphans(lfs, -1);
@@ -3058,7 +3010,7 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
}
uint16_t id = lfs_tag_id(tag);
- if (id == 0x1ff) {
+ if (id == 0x3ff) {
// special case for root
id = 0;
int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
@@ -3067,8 +3019,9 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
}
}
- tag = lfs_dir_get(lfs, &cwd, 0x7fffe000,
- LFS_MKTAG(0x100 | type, id, lfs_min(size, lfs->attr_max)),
+ tag = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x7ff, 0x3ff, 0),
+ LFS_MKTAG(LFS_TYPE_USERATTR + type,
+ id, lfs_min(size, lfs->attr_max)),
buffer);
if (tag < 0) {
if (tag == LFS_ERR_NOENT) {
@@ -3089,7 +3042,7 @@ static int lfs_commitattr(lfs_t *lfs, const char *path,
}
uint16_t id = lfs_tag_id(tag);
- if (id == 0x1ff) {
+ if (id == 0x3ff) {
// special case for root
id = 0;
int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
@@ -3099,7 +3052,7 @@ static int lfs_commitattr(lfs_t *lfs, const char *path,
}
return lfs_dir_commit(lfs, &cwd,
- LFS_MKATTR(0x100 | type, id, buffer, size,
+ LFS_MKATTR(LFS_TYPE_USERATTR + type, id, buffer, size,
NULL));
}
@@ -3113,7 +3066,7 @@ int lfs_setattr(lfs_t *lfs, const char *path,
}
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
- return lfs_commitattr(lfs, path, type, NULL, 0x1fff);
+ return lfs_commitattr(lfs, path, type, NULL, 0x3ff);
}
@@ -3268,7 +3221,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
&superblock, sizeof(superblock),
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
- NULL)));
+ LFS_MKATTR(LFS_TYPE_CREATE, 0, NULL, 0,
+ NULL))));
if (err) {
goto cleanup;
}
@@ -3295,8 +3249,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
lfs_mdir_t dir = {.tail = {0, 1}};
while (!lfs_pair_isnull(dir.tail)) {
// fetch next block in tail list
- lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7fffe000,
+ lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
+ LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
+ NULL,
lfs_dir_find_match, &(struct lfs_dir_find_match){
lfs, "littlefs", 8});
if (tag < 0) {
@@ -3312,7 +3268,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
// grab superblock
lfs_superblock_t superblock;
- tag = lfs_dir_get(lfs, &dir, 0x7fffe000,
+ tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock);
if (tag < 0) {
@@ -3439,7 +3395,7 @@ int lfs_fs_traverse(lfs_t *lfs,
for (uint16_t id = 0; id < dir.count; id++) {
struct lfs_ctz ctz;
- lfs_stag_t tag = lfs_dir_get(lfs, &dir, 0x783fe000,
+ lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz);
if (tag < 0) {
if (tag == LFS_ERR_NOENT) {
@@ -3449,7 +3405,7 @@ int lfs_fs_traverse(lfs_t *lfs,
}
lfs_ctz_fromle32(&ctz);
- if (lfs_tag_type(tag) == LFS_TYPE_CTZSTRUCT) {
+ if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) {
err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache,
ctz.head, ctz.size, cb, data);
if (err) {
@@ -3525,7 +3481,7 @@ static int lfs_fs_parent_match(void *data,
}
lfs_pair_fromle32(child);
- return (lfs_pair_cmp(child, find->pair) == 0) ? tag : 0;
+ return (lfs_pair_cmp(child, find->pair) == 0) ? LFS_CMP_EQ : LFS_CMP_LT;
}
static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
@@ -3535,10 +3491,12 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
parent->tail[1] = 1;
while (!lfs_pair_isnull(parent->tail)) {
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail,
- 0x7fc01fff, LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8),
+ LFS_MKTAG(0x7ff, 0, 0x3ff),
+ LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8),
+ NULL,
lfs_fs_parent_match, &(struct lfs_fs_parent_match){
lfs, {pair[0], pair[1]}});
- if (tag) {
+ if (tag && tag != LFS_ERR_NOENT) {
return tag;
}
}
@@ -3600,7 +3558,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
parent.tail[1] = newpair[1];
err = lfs_dir_commit(lfs, &parent,
LFS_MKATTR(LFS_TYPE_TAIL + parent.split,
- 0x1ff, parent.tail, sizeof(parent.tail),
+ 0x3ff, parent.tail, sizeof(parent.tail),
NULL));
if (err) {
return err;
@@ -3674,7 +3632,8 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
}
lfs_block_t pair[2];
- lfs_stag_t res = lfs_dir_get(lfs, &parent, 0x7fffe000, tag, pair);
+ lfs_stag_t res = lfs_dir_get(lfs, &parent,
+ LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair);
if (res < 0) {
return res;
}
@@ -3689,7 +3648,7 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
pdir.tail[1] = pair[1];
err = lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_SOFTTAIL,
- 0x1ff, pdir.tail, sizeof(pdir.tail),
+ 0x3ff, pdir.tail, sizeof(pdir.tail),
NULL));
if (err) {
return err;
@@ -3735,5 +3694,5 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs) {
return err;
}
- return size;
+ return size;
}
diff --git a/lfs.h b/lfs.h
index 85c31e3..05ba540 100644
--- a/lfs.h
+++ b/lfs.h
@@ -45,25 +45,25 @@ typedef int32_t lfs_soff_t;
typedef uint32_t lfs_block_t;
// Maximum name size in bytes, may be redefined to reduce the size of the
-// info struct. Limited to <= 8190. Stored in superblock and must be
+// info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers.
#ifndef LFS_NAME_MAX
-#define LFS_NAME_MAX 0xff
+#define LFS_NAME_MAX 255
#endif
// Maximum inline file size in bytes, may be redefined to limit RAM usage,
// but littlefs will automatically limit the LFS_INLINE_MAX to the
-// configured cache_size. Limited to <= 8190. Stored in superblock and must
+// configured cache_size. Limited to <= 1022. Stored in superblock and must
// be respected by other littlefs drivers.
#ifndef LFS_INLINE_MAX
-#define LFS_INLINE_MAX 0x1ffe
+#define LFS_INLINE_MAX 1022
#endif
// Maximum size of custom attributes in bytes, may be redefined, but there is
-// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 8190. Stored
+// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored
// in superblock and must be respected by other littlefs drivers.
#ifndef LFS_ATTR_MAX
-#define LFS_ATTR_MAX 0x1ffe
+#define LFS_ATTR_MAX 1022
#endif
// Maximum size of a file in bytes, may be redefined to limit to support other
@@ -98,31 +98,33 @@ enum lfs_error {
// File types
enum lfs_type {
// file types
- LFS_TYPE_REG = 0x011,
- LFS_TYPE_DIR = 0x010,
+ LFS_TYPE_REG = 0x001,
+ LFS_TYPE_DIR = 0x002,
// internally used types
- LFS_TYPE_USERATTR = 0x100,
- LFS_TYPE_CREATE = 0x000,
- LFS_TYPE_DELETE = 0x020,
- LFS_TYPE_STRUCT = 0x040,
- LFS_TYPE_TAIL = 0x080,
- LFS_TYPE_SOFTTAIL = 0x080,
- LFS_TYPE_HARDTAIL = 0x081,
- LFS_TYPE_CRC = 0x0a0,
- LFS_TYPE_SUPERBLOCK = 0x001,
- LFS_TYPE_GLOBALS = 0x0e0,
-
- LFS_TYPE_DIRSTRUCT = 0x040,
- LFS_TYPE_INLINESTRUCT = 0x041,
- LFS_TYPE_CTZSTRUCT = 0x042,
+ LFS_TYPE_SPLICE = 0x400,
+ LFS_TYPE_NAME = 0x000,
+ LFS_TYPE_STRUCT = 0x200,
+ LFS_TYPE_USERATTR = 0x300,
+ LFS_TYPE_FROM = 0x100,
+ LFS_TYPE_TAIL = 0x600,
+ LFS_TYPE_GLOBALS = 0x700,
+ LFS_TYPE_CRC = 0x500,
+
+ // internally used type specializations
+ LFS_TYPE_CREATE = 0x401,
+ LFS_TYPE_DELETE = 0x4ff,
+ LFS_TYPE_SUPERBLOCK = 0x0ff,
+ LFS_TYPE_DIRSTRUCT = 0x200,
+ LFS_TYPE_CTZSTRUCT = 0x202,
+ LFS_TYPE_INLINESTRUCT = 0x201,
+ LFS_TYPE_SOFTTAIL = 0x600,
+ LFS_TYPE_HARDTAIL = 0x601,
+ LFS_TYPE_MOVESTATE = 0x7ff,
// internal chip sources
- LFS_TYPE_FROM = 0x060,
- LFS_FROM_MEM = 0x000,
- LFS_FROM_DISK = 0x200,
- LFS_FROM_MOVE = 0x061,
- LFS_FROM_USERATTRS = 0x062,
+ LFS_FROM_MOVE = 0x101,
+ LFS_FROM_USERATTRS = 0x102,
};
// File open flags
@@ -314,8 +316,8 @@ typedef struct lfs_cache {
typedef struct lfs_mdir {
lfs_block_t pair[2];
uint32_t rev;
- uint32_t etag;
lfs_off_t off;
+ uint32_t etag;
uint16_t count;
bool erased;
bool split;
diff --git a/tests/corrupt.py b/tests/corrupt.py
index b6671ff..44f4f66 100755
--- a/tests/corrupt.py
+++ b/tests/corrupt.py
@@ -19,7 +19,7 @@ def corrupt(block):
break
tag ^= ntag
- size = (tag & 0x1fff) if (tag & 0x1fff) != 0x1fff else 0
+ size = (tag & 0x3ff) if (tag & 0x3ff) != 0x3ff else 0
file.seek(size, os.SEEK_CUR)
# lob off last 3 bytes
diff --git a/tests/debug.py b/tests/debug.py
index c76dc3d..f8c0484 100755
--- a/tests/debug.py
+++ b/tests/debug.py
@@ -4,23 +4,29 @@ import struct
import binascii
TYPES = {
- (0x1ff, 0x011): 'create reg',
- (0x1ff, 0x010): 'create dir',
- (0x1ff, 0x001): 'superblock',
- (0x1ff, 0x020): 'delete',
- (0x1f0, 0x0e0): 'globals',
- (0x1ff, 0x080): 'tail soft',
- (0x1ff, 0x081): 'tail hard',
- (0x1f0, 0x0a0): 'crc',
- (0x1ff, 0x040): 'struct dir',
- (0x1ff, 0x041): 'struct inline',
- (0x1ff, 0x042): 'struct ctz',
- (0x100, 0x100): 'attr',
+ (0x700, 0x400): 'splice',
+ (0x7ff, 0x401): 'create',
+ (0x7ff, 0x4ff): 'delete',
+ (0x700, 0x000): 'name',
+ (0x7ff, 0x001): 'name reg',
+ (0x7ff, 0x002): 'name dir',
+ (0x7ff, 0x0ff): 'name superblock',
+ (0x700, 0x200): 'struct',
+ (0x7ff, 0x200): 'struct dir',
+ (0x7ff, 0x202): 'struct ctz',
+ (0x7ff, 0x201): 'struct inline',
+ (0x700, 0x300): 'userattr',
+ (0x700, 0x600): 'tail',
+ (0x7ff, 0x600): 'tail soft',
+ (0x7ff, 0x601): 'tail hard',
+ (0x700, 0x700): 'gstate',
+ (0x7ff, 0x7ff): 'gstate move',
+ (0x700, 0x500): 'crc',
}
def typeof(type):
- for prefix in range(9):
- mask = 0x1ff & ~((1 << prefix)-1)
+ for prefix in range(12):
+ mask = 0x7ff & ~((1 << prefix)-1)
if (mask, type & mask) in TYPES:
return TYPES[mask, type & mask] + (
' %0*x' % (prefix/4, type & ((1 << prefix)-1))
@@ -59,7 +65,7 @@ def main(*blocks):
print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True))
# go through each tag, print useful information
- print "%-4s %-8s %-14s %3s %3s %s" % (
+ print "%-4s %-8s %-14s %3s %4s %s" % (
'off', 'tag', 'type', 'id', 'len', 'dump')
tag = 0xffffffff
@@ -75,26 +81,26 @@ def main(*blocks):
tag ^= ntag
off += 4
- type = (tag & 0x7fc00000) >> 22
- id = (tag & 0x003fe000) >> 13
- size = (tag & 0x00001fff) >> 0
- iscrc = (type & 0x1f0) == 0x0f0
+ type = (tag & 0x7ff00000) >> 20
+ id = (tag & 0x000ffc00) >> 10
+ size = (tag & 0x000003ff) >> 0
+ iscrc = (type & 0x700) == 0x500
- data = file.read(size if size != 0x1fff else 0)
+ data = file.read(size if size != 0x3ff else 0)
if iscrc:
crc = binascii.crc32(data[:4], crc)
else:
crc = binascii.crc32(data, crc)
- print '%04x: %08x %-14s %3s %3s %-23s %-8s' % (
+ print '%04x: %08x %-15s %3s %4s %-23s %-8s' % (
off, tag,
typeof(type) + (' bad!' if iscrc and ~crc else ''),
- id if id != 0x1ff else '.',
- size if size != 0x1fff else 'x',
+ id if id != 0x3ff else '.',
+ size if size != 0x3ff else 'x',
' '.join('%02x' % ord(c) for c in data[:8]),
''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8]))
- off += size if size != 0x1fff else 0
+ off += size if size != 0x3ff else 0
if iscrc:
crc = 0
tag ^= (type & 1) << 31
diff --git a/tests/test_alloc.sh b/tests/test_alloc.sh
index f924a29..3f993e9 100755
--- a/tests/test_alloc.sh
+++ b/tests/test_alloc.sh
@@ -253,7 +253,7 @@ tests/test.py << TEST
// find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0;
- for (int i = 0; i < 9; i++) {
+ for (int i = 0; i < 10; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, (char*)buffer) => 0;
}
@@ -275,7 +275,7 @@ tests/test.py << TEST
lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0;
- for (int i = 0; i < 9; i++) {
+ for (int i = 0; i < 10; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_remove(&lfs, (char*)buffer) => 0;
}
@@ -287,7 +287,7 @@ tests/test.py << TEST
}
lfs_file_sync(&lfs, &file[0]) => 0;
- for (int i = 0; i < 9; i++) {
+ for (int i = 0; i < 10; i++) {
sprintf((char*)buffer, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, (char*)buffer) => 0;
}
diff --git a/tests/test_format.sh b/tests/test_format.sh
index d885f83..5a11535 100755
--- a/tests/test_format.sh
+++ b/tests/test_format.sh
@@ -12,8 +12,7 @@ TEST
echo "--- Basic mounting ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
-TEST
-tests/test.py << TEST
+
lfs_mount(&lfs, &cfg) => 0;
lfs_unmount(&lfs) => 0;
TEST