forked from Imagelibrary/littlefs
Compare commits
25 Commits
fix-dir-se
...
fs-stat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
265692e709 | ||
|
|
c5fb3f181b | ||
|
|
8610f7c36b | ||
|
|
a51be18765 | ||
|
|
a7ccc1df59 | ||
|
|
fdee127f74 | ||
|
|
87bbf1d374 | ||
|
|
66f07563c3 | ||
|
|
5eed341059 | ||
|
|
97e2526a81 | ||
|
|
8a4ee65fc3 | ||
|
|
6fda813ce8 | ||
|
|
f2bc6a8e88 | ||
|
|
ec3ec86bcc | ||
|
|
405f33214a | ||
|
|
3dca02911f | ||
|
|
259535ee73 | ||
|
|
94d9e097a6 | ||
|
|
dd03c27476 | ||
|
|
23a4a089b5 | ||
|
|
922a35b3a5 | ||
|
|
e57402c8e9 | ||
|
|
6dc18c38c1 | ||
|
|
d5dc4872cb | ||
|
|
7b151e1abb |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# GitHub really wants to mark littlefs as a python project, telling it to
|
||||
# reclassify our test .toml files as C code (which they are 95% of anyways)
|
||||
# remedies this
|
||||
*.toml linguist-language=c
|
||||
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
@@ -371,7 +371,8 @@ jobs:
|
||||
# on one geometry
|
||||
- name: test-valgrind
|
||||
run: |
|
||||
TESTFLAGS="$TESTFLAGS --valgrind -Gdefault -Pnone" make test
|
||||
TESTFLAGS="$TESTFLAGS --valgrind --context=1024 -Gdefault -Pnone" \
|
||||
make test
|
||||
|
||||
# test that compilation is warning free under clang
|
||||
# run with Clang, mostly to check for Clang-specific warnings
|
||||
|
||||
185
lfs.c
185
lfs.c
@@ -415,11 +415,11 @@ static inline uint8_t lfs_gstate_getorphans(const lfs_gstate_t *a) {
|
||||
static inline bool lfs_gstate_hasmove(const lfs_gstate_t *a) {
|
||||
return lfs_tag_type1(a->tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool lfs_gstate_needssuperblock(const lfs_gstate_t *a) {
|
||||
return lfs_tag_size(a->tag) >> 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool lfs_gstate_hasmovehere(const lfs_gstate_t *a,
|
||||
const lfs_block_t *pair) {
|
||||
@@ -535,7 +535,6 @@ static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
|
||||
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss);
|
||||
static void lfs_fs_prepsuperblock(lfs_t *lfs, bool needssuperblock);
|
||||
static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans);
|
||||
static void lfs_fs_prepmove(lfs_t *lfs,
|
||||
uint16_t id, const lfs_block_t pair[2]);
|
||||
@@ -546,6 +545,8 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2],
|
||||
static int lfs_fs_forceconsistency(lfs_t *lfs);
|
||||
#endif
|
||||
|
||||
static void lfs_fs_prepsuperblock(lfs_t *lfs, bool needssuperblock);
|
||||
|
||||
#ifdef LFS_MIGRATE
|
||||
static int lfs1_traverse(lfs_t *lfs,
|
||||
int (*cb)(void*, lfs_block_t), void *data);
|
||||
@@ -1651,7 +1652,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
|
||||
|
||||
commit->off = noff;
|
||||
// perturb valid bit?
|
||||
commit->ptag = ntag ^ ((0x80 & ~eperturb) << 24);
|
||||
commit->ptag = ntag ^ ((0x80UL & ~eperturb) << 24);
|
||||
// reset crc for next commit
|
||||
commit->crc = 0xffffffff;
|
||||
|
||||
@@ -3465,7 +3466,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
|
||||
// find out which block we're extending from
|
||||
int err = lfs_ctz_find(lfs, NULL, &file->cache,
|
||||
file->ctz.head, file->ctz.size,
|
||||
file->pos-1, &file->block, &file->off);
|
||||
file->pos-1, &file->block, &(lfs_off_t){0});
|
||||
if (err) {
|
||||
file->flags |= LFS_F_ERRED;
|
||||
return err;
|
||||
@@ -3643,26 +3644,55 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||
lfs_off_t pos = file->pos;
|
||||
lfs_off_t oldsize = lfs_file_rawsize(lfs, file);
|
||||
if (size < oldsize) {
|
||||
// need to flush since directly changing metadata
|
||||
int err = lfs_file_flush(lfs, file);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
// revert to inline file?
|
||||
if (size <= lfs_min(0x3fe, lfs_min(
|
||||
lfs->cfg->cache_size,
|
||||
(lfs->cfg->metadata_max ?
|
||||
lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
|
||||
// flush+seek to head
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
|
||||
if (res < 0) {
|
||||
return (int)res;
|
||||
}
|
||||
|
||||
// lookup new head in ctz skip list
|
||||
err = lfs_ctz_find(lfs, NULL, &file->cache,
|
||||
file->ctz.head, file->ctz.size,
|
||||
size, &file->block, &file->off);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
// read our data into rcache temporarily
|
||||
lfs_cache_drop(lfs, &lfs->rcache);
|
||||
res = lfs_file_flushedread(lfs, file,
|
||||
lfs->rcache.buffer, size);
|
||||
if (res < 0) {
|
||||
return (int)res;
|
||||
}
|
||||
|
||||
// need to set pos/block/off consistently so seeking back to
|
||||
// the old position does not get confused
|
||||
file->pos = size;
|
||||
file->ctz.head = file->block;
|
||||
file->ctz.size = size;
|
||||
file->flags |= LFS_F_DIRTY | LFS_F_READING;
|
||||
file->ctz.head = LFS_BLOCK_INLINE;
|
||||
file->ctz.size = size;
|
||||
file->flags |= LFS_F_DIRTY | LFS_F_READING | LFS_F_INLINE;
|
||||
file->cache.block = file->ctz.head;
|
||||
file->cache.off = 0;
|
||||
file->cache.size = lfs->cfg->cache_size;
|
||||
memcpy(file->cache.buffer, lfs->rcache.buffer, size);
|
||||
|
||||
} else {
|
||||
// need to flush since directly changing metadata
|
||||
int err = lfs_file_flush(lfs, file);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// lookup new head in ctz skip list
|
||||
err = lfs_ctz_find(lfs, NULL, &file->cache,
|
||||
file->ctz.head, file->ctz.size,
|
||||
size-1, &file->block, &(lfs_off_t){0});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// need to set pos/block/off consistently so seeking back to
|
||||
// the old position does not get confused
|
||||
file->pos = size;
|
||||
file->ctz.head = file->block;
|
||||
file->ctz.size = size;
|
||||
file->flags |= LFS_F_DIRTY | LFS_F_READING;
|
||||
}
|
||||
} else if (size > oldsize) {
|
||||
// flush+seek if not already at end
|
||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
|
||||
@@ -4295,11 +4325,9 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
"v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16,
|
||||
major_version, minor_version,
|
||||
LFS_DISK_VERSION_MAJOR, LFS_DISK_VERSION_MINOR);
|
||||
#ifndef LFS_READONLY
|
||||
// note this bit is reserved on disk, so fetching more gstate
|
||||
// will not interfere here
|
||||
lfs_fs_prepsuperblock(lfs, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// check superblock configuration
|
||||
@@ -4392,6 +4420,42 @@ static int lfs_rawunmount(lfs_t *lfs) {
|
||||
|
||||
|
||||
/// Filesystem filesystem operations ///
|
||||
static int lfs_fs_rawstat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
|
||||
// if the superblock is up-to-date, we must be on the most recent
|
||||
// minor version of littlefs
|
||||
if (!lfs_gstate_needssuperblock(&lfs->gstate)) {
|
||||
fsinfo->disk_version = LFS_DISK_VERSION;
|
||||
|
||||
// otherwise we need to read the minor version on disk
|
||||
} else {
|
||||
// fetch the superblock
|
||||
lfs_mdir_t dir;
|
||||
int err = lfs_dir_fetch(lfs, &dir, lfs->root);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
lfs_superblock_t superblock;
|
||||
lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
|
||||
&superblock);
|
||||
if (tag < 0) {
|
||||
return tag;
|
||||
}
|
||||
lfs_superblock_fromle32(&superblock);
|
||||
|
||||
// read the on-disk version
|
||||
fsinfo->disk_version = superblock.version;
|
||||
}
|
||||
|
||||
// other on-disk configuration, we cache all of these for internal use
|
||||
fsinfo->name_max = lfs->name_max;
|
||||
fsinfo->file_max = lfs->file_max;
|
||||
fsinfo->attr_max = lfs->attr_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_fs_rawtraverse(lfs_t *lfs,
|
||||
int (*cb)(void *data, lfs_block_t block), void *data,
|
||||
bool includeorphans) {
|
||||
@@ -4602,12 +4666,10 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static void lfs_fs_prepsuperblock(lfs_t *lfs, bool needssuperblock) {
|
||||
lfs->gstate.tag = (lfs->gstate.tag & ~LFS_MKTAG(0, 0, 0x200))
|
||||
| (uint32_t)needssuperblock << 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
|
||||
@@ -4712,8 +4774,6 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t found = 0;
|
||||
|
||||
// Check for orphans in two separate passes:
|
||||
// - 1 for half-orphans (relocations)
|
||||
// - 2 for full-orphans (removes/renames)
|
||||
@@ -4784,8 +4844,6 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
|
||||
return state;
|
||||
}
|
||||
|
||||
found += 1;
|
||||
|
||||
// did our commit create more orphans?
|
||||
if (state == LFS_OK_ORPHANED) {
|
||||
moreorphans = true;
|
||||
@@ -4820,8 +4878,6 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
|
||||
return state;
|
||||
}
|
||||
|
||||
found += 1;
|
||||
|
||||
// did our commit create more orphans?
|
||||
if (state == LFS_OK_ORPHANED) {
|
||||
moreorphans = true;
|
||||
@@ -4839,9 +4895,7 @@ static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) {
|
||||
}
|
||||
|
||||
// mark orphans as fixed
|
||||
return lfs_fs_preporphans(lfs, -lfs_min(
|
||||
lfs_gstate_getorphans(&lfs->gstate),
|
||||
found));
|
||||
return lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4866,6 +4920,36 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
int lfs_fs_rawmkconsistent(lfs_t *lfs) {
|
||||
// lfs_fs_forceconsistency does most of the work here
|
||||
int err = lfs_fs_forceconsistency(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// do we have any pending gstate?
|
||||
lfs_gstate_t delta = {0};
|
||||
lfs_gstate_xor(&delta, &lfs->gdisk);
|
||||
lfs_gstate_xor(&delta, &lfs->gstate);
|
||||
if (!lfs_gstate_iszero(&delta)) {
|
||||
// lfs_dir_commit will implicitly write out any pending gstate
|
||||
lfs_mdir_t root;
|
||||
err = lfs_dir_fetch(lfs, &root, lfs->root);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfs_dir_commit(lfs, &root, NULL, 0);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int lfs_fs_size_count(void *p, lfs_block_t block) {
|
||||
(void)block;
|
||||
lfs_size_t *size = p;
|
||||
@@ -4883,6 +4967,7 @@ static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) {
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
#ifdef LFS_MIGRATE
|
||||
////// Migration from littelfs v1 below this //////
|
||||
|
||||
@@ -6002,6 +6087,20 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
|
||||
int err = LFS_LOCK(lfs->cfg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
LFS_TRACE("lfs_fs_stat(%p, %p)", (void*)lfs, (void*)fsinfo);
|
||||
|
||||
err = lfs_fs_rawstat(lfs, fsinfo);
|
||||
|
||||
LFS_TRACE("lfs_fs_stat -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
return err;
|
||||
}
|
||||
|
||||
lfs_ssize_t lfs_fs_size(lfs_t *lfs) {
|
||||
int err = LFS_LOCK(lfs->cfg);
|
||||
if (err) {
|
||||
@@ -6031,6 +6130,22 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) {
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
int lfs_fs_mkconsistent(lfs_t *lfs) {
|
||||
int err = LFS_LOCK(lfs->cfg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
LFS_TRACE("lfs_fs_mkconsistent(%p)", (void*)lfs);
|
||||
|
||||
err = lfs_fs_rawmkconsistent(lfs);
|
||||
|
||||
LFS_TRACE("lfs_fs_mkconsistent -> %d", err);
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LFS_MIGRATE
|
||||
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
int err = LFS_LOCK(cfg);
|
||||
|
||||
33
lfs.h
33
lfs.h
@@ -280,6 +280,21 @@ struct lfs_info {
|
||||
char name[LFS_NAME_MAX+1];
|
||||
};
|
||||
|
||||
// Filesystem info structure
|
||||
struct lfs_fsinfo {
|
||||
// On-disk version.
|
||||
uint32_t disk_version;
|
||||
|
||||
// Upper limit on the length of file names in bytes.
|
||||
lfs_size_t name_max;
|
||||
|
||||
// Upper limit on the size of files in bytes.
|
||||
lfs_size_t file_max;
|
||||
|
||||
// Upper limit on the size of custom attributes in bytes.
|
||||
lfs_size_t attr_max;
|
||||
};
|
||||
|
||||
// Custom attribute structure, used to describe custom attributes
|
||||
// committed atomically during file writes.
|
||||
struct lfs_attr {
|
||||
@@ -659,6 +674,12 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
/// Filesystem-level filesystem operations
|
||||
|
||||
// Find on-disk info about the filesystem
|
||||
//
|
||||
// Fills out the fsinfo structure based on the filesystem found on-disk.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo);
|
||||
|
||||
// Finds the current size of the filesystem
|
||||
//
|
||||
// Note: Result is best effort. If files share COW structures, the returned
|
||||
@@ -676,6 +697,18 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs);
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
// Attempt to make the filesystem consistent and ready for writing
|
||||
//
|
||||
// Calling this function is not required, consistency will be implicitly
|
||||
// enforced on the first operation that writes to the filesystem, but this
|
||||
// function allows the work to be performed earlier and without other
|
||||
// filesystem changes.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_fs_mkconsistent(lfs_t *lfs);
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
#ifdef LFS_MIGRATE
|
||||
// Attempts to migrate a previous version of littlefs
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
// System includes
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
@@ -22,14 +22,16 @@ code = '''
|
||||
#define STRINGIZE_(x) #x
|
||||
#include STRINGIZE(LFSP)
|
||||
#else
|
||||
#define LFSP_VERSION LFS_VERSION
|
||||
#define LFSP_VERSION_MAJOR LFS_VERSION_MAJOR
|
||||
#define LFSP_VERSION_MINOR LFS_VERSION_MINOR
|
||||
#define LFSP_DISK_VERSION LFS_DISK_VERSION
|
||||
#define LFSP_DISK_VERSION_MAJOR LFS_DISK_VERSION_MAJOR
|
||||
#define LFSP_DISK_VERSION_MINOR LFS_DISK_VERSION_MINOR
|
||||
#define lfsp_t lfs_t
|
||||
#define lfsp_config lfs_config
|
||||
#define lfsp_format lfs_format
|
||||
#define lfsp_mount lfs_mount
|
||||
#define lfsp_unmount lfs_unmount
|
||||
#define lfsp_fsinfo lfs_fsinfo
|
||||
#define lfsp_fs_stat lfs_fs_stat
|
||||
#define lfsp_dir_t lfs_dir_t
|
||||
#define lfsp_info lfs_info
|
||||
#define LFSP_TYPE_REG LFS_TYPE_REG
|
||||
@@ -58,7 +60,7 @@ code = '''
|
||||
|
||||
# test we can mount in a new version
|
||||
[cases.test_compat_forward_mount]
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -74,13 +76,19 @@ code = '''
|
||||
// now test the new mount
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test we can read dirs in a new version
|
||||
[cases.test_compat_forward_read_dirs]
|
||||
defines.COUNT = 5
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -102,6 +110,11 @@ code = '''
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
// can we list the directories?
|
||||
lfs_dir_t dir;
|
||||
lfs_dir_open(&lfs, &dir, "/") => 0;
|
||||
@@ -132,7 +145,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -166,6 +179,11 @@ code = '''
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
// can we list the files?
|
||||
lfs_dir_t dir;
|
||||
lfs_dir_open(&lfs, &dir, "/") => 0;
|
||||
@@ -214,7 +232,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -251,6 +269,11 @@ code = '''
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
// can we list the directories?
|
||||
lfs_dir_t dir;
|
||||
lfs_dir_open(&lfs, &dir, "/") => 0;
|
||||
@@ -321,7 +344,7 @@ code = '''
|
||||
# test we can write dirs in a new version
|
||||
[cases.test_compat_forward_write_dirs]
|
||||
defines.COUNT = 10
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -343,6 +366,11 @@ code = '''
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
// write another COUNT/2 dirs
|
||||
for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
|
||||
char name[8];
|
||||
@@ -380,7 +408,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -420,6 +448,11 @@ code = '''
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
// write half COUNT files
|
||||
prng = 42;
|
||||
for (lfs_size_t i = 0; i < COUNT; i++) {
|
||||
@@ -494,7 +527,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
|
||||
if = 'LFS_DISK_VERSION_MAJOR == LFSP_DISK_VERSION_MAJOR'
|
||||
code = '''
|
||||
// create the previous version
|
||||
struct lfsp_config cfgp;
|
||||
@@ -537,6 +570,11 @@ code = '''
|
||||
lfs_t lfs;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// we should be able to read the version using lfs_fs_stat
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFSP_DISK_VERSION);
|
||||
|
||||
// write half COUNT files
|
||||
prng = 42;
|
||||
for (lfs_size_t i = 0; i < COUNT; i++) {
|
||||
@@ -636,7 +674,7 @@ code = '''
|
||||
|
||||
# test we can mount in an old version
|
||||
[cases.test_compat_backward_mount]
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs_t lfs;
|
||||
@@ -651,13 +689,14 @@ code = '''
|
||||
memcpy(&cfgp, cfg, sizeof(cfgp));
|
||||
lfsp_t lfsp;
|
||||
lfsp_mount(&lfsp, &cfgp) => 0;
|
||||
|
||||
lfsp_unmount(&lfsp) => 0;
|
||||
'''
|
||||
|
||||
# test we can read dirs in an old version
|
||||
[cases.test_compat_backward_read_dirs]
|
||||
defines.COUNT = 5
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs_t lfs;
|
||||
@@ -709,7 +748,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs_t lfs;
|
||||
@@ -791,7 +830,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 4
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs_t lfs;
|
||||
@@ -898,7 +937,7 @@ code = '''
|
||||
# test we can write dirs in an old version
|
||||
[cases.test_compat_backward_write_dirs]
|
||||
defines.COUNT = 10
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the new version
|
||||
lfs_t lfs;
|
||||
@@ -957,7 +996,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the previous version
|
||||
lfs_t lfs;
|
||||
@@ -1071,7 +1110,7 @@ code = '''
|
||||
defines.COUNT = 5
|
||||
defines.SIZE = [4, 32, 512, 8192]
|
||||
defines.CHUNK = 2
|
||||
if = 'LFS_VERSION == LFSP_VERSION'
|
||||
if = 'LFS_DISK_VERSION == LFSP_DISK_VERSION'
|
||||
code = '''
|
||||
// create the previous version
|
||||
lfs_t lfs;
|
||||
@@ -1316,45 +1355,54 @@ code = '''
|
||||
|
||||
// mount should still work
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION-1);
|
||||
|
||||
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
|
||||
uint8_t buffer[8];
|
||||
lfs_file_read(&lfs, &file, buffer, 8) => 8;
|
||||
assert(memcmp(buffer, "testtest", 8) == 0);
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
|
||||
// minor version should be unchanged
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION-1);
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// if we write, we need to bump the minor version
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION-1);
|
||||
|
||||
lfs_file_open(&lfs, &file, "test", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
|
||||
lfs_file_write(&lfs, &file, "teeeeest", 8) => 8;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
|
||||
// minor version should have changed
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
|
||||
&superblock)
|
||||
=> LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock));
|
||||
lfs_superblock_fromle32(&superblock);
|
||||
assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR);
|
||||
assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR);
|
||||
// minor version should be changed
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION);
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// and of course mount should still work
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
// minor version should have changed
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION);
|
||||
|
||||
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, 8) => 8;
|
||||
assert(memcmp(buffer, "teeeeest", 8) == 0);
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
|
||||
// minor version should have changed
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
|
||||
&superblock)
|
||||
=> LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock));
|
||||
lfs_superblock_fromle32(&superblock);
|
||||
assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR);
|
||||
assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR);
|
||||
// yep, still changed
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION);
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
@@ -59,6 +59,150 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that we only run deorphan once per power-cycle
|
||||
[cases.test_orphans_no_orphans]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// mark the filesystem as having orphans
|
||||
lfs_fs_preporphans(&lfs, +1) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
|
||||
|
||||
// we should have orphans at this state
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// mount
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// we should detect orphans
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
// force consistency
|
||||
lfs_fs_forceconsistency(&lfs) => 0;
|
||||
// we should no longer have orphans
|
||||
assert(!lfs_gstate_hasorphans(&lfs.gstate));
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_orphans_one_orphan]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// create an orphan
|
||||
lfs_mdir_t orphan;
|
||||
lfs_alloc_ack(&lfs);
|
||||
lfs_dir_alloc(&lfs, &orphan) => 0;
|
||||
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
|
||||
|
||||
// append our orphan and mark the filesystem as having orphans
|
||||
lfs_fs_preporphans(&lfs, +1) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_pair_tole32(orphan.pair);
|
||||
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
|
||||
|
||||
// we should have orphans at this state
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// mount
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// we should detect orphans
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
// force consistency
|
||||
lfs_fs_forceconsistency(&lfs) => 0;
|
||||
// we should no longer have orphans
|
||||
assert(!lfs_gstate_hasorphans(&lfs.gstate));
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that we can persist gstate with lfs_fs_mkconsistent
|
||||
[cases.test_orphans_mkconsistent_no_orphans]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// mark the filesystem as having orphans
|
||||
lfs_fs_preporphans(&lfs, +1) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
|
||||
|
||||
// we should have orphans at this state
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// mount
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// we should detect orphans
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
// force consistency
|
||||
lfs_fs_mkconsistent(&lfs) => 0;
|
||||
// we should no longer have orphans
|
||||
assert(!lfs_gstate_hasorphans(&lfs.gstate));
|
||||
|
||||
// remount
|
||||
lfs_unmount(&lfs) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// we should still have no orphans
|
||||
assert(!lfs_gstate_hasorphans(&lfs.gstate));
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_orphans_mkconsistent_one_orphan]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// create an orphan
|
||||
lfs_mdir_t orphan;
|
||||
lfs_alloc_ack(&lfs);
|
||||
lfs_dir_alloc(&lfs, &orphan) => 0;
|
||||
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
|
||||
|
||||
// append our orphan and mark the filesystem as having orphans
|
||||
lfs_fs_preporphans(&lfs, +1) => 0;
|
||||
lfs_mdir_t mdir;
|
||||
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||
lfs_pair_tole32(orphan.pair);
|
||||
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
|
||||
|
||||
// we should have orphans at this state
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// mount
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// we should detect orphans
|
||||
assert(lfs_gstate_hasorphans(&lfs.gstate));
|
||||
// force consistency
|
||||
lfs_fs_mkconsistent(&lfs) => 0;
|
||||
// we should no longer have orphans
|
||||
assert(!lfs_gstate_hasorphans(&lfs.gstate));
|
||||
|
||||
// remount
|
||||
lfs_unmount(&lfs) => 0;
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
// we should still have no orphans
|
||||
assert(!lfs_gstate_hasorphans(&lfs.gstate));
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# reentrant testing for orphans, basically just spam mkdir/remove
|
||||
[cases.test_orphans_reentrant]
|
||||
reentrant = true
|
||||
|
||||
@@ -34,6 +34,52 @@ code = '''
|
||||
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
|
||||
'''
|
||||
|
||||
# test we can read superblock info through lfs_fs_stat
|
||||
[cases.test_superblocks_stat]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
|
||||
// test we can mount and read fsinfo
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION);
|
||||
assert(fsinfo.name_max == LFS_NAME_MAX);
|
||||
assert(fsinfo.file_max == LFS_FILE_MAX);
|
||||
assert(fsinfo.attr_max == LFS_ATTR_MAX);
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_superblocks_stat_tweaked]
|
||||
defines.TWEAKED_NAME_MAX = 63
|
||||
defines.TWEAKED_FILE_MAX = '(1 << 16)-1'
|
||||
defines.TWEAKED_ATTR_MAX = 512
|
||||
code = '''
|
||||
// create filesystem with tweaked params
|
||||
struct lfs_config tweaked_cfg = *cfg;
|
||||
tweaked_cfg.name_max = TWEAKED_NAME_MAX;
|
||||
tweaked_cfg.file_max = TWEAKED_FILE_MAX;
|
||||
tweaked_cfg.attr_max = TWEAKED_ATTR_MAX;
|
||||
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, &tweaked_cfg) => 0;
|
||||
|
||||
// test we can mount and read these params with the original config
|
||||
lfs_mount(&lfs, cfg) => 0;
|
||||
|
||||
struct lfs_fsinfo fsinfo;
|
||||
lfs_fs_stat(&lfs, &fsinfo) => 0;
|
||||
assert(fsinfo.disk_version == LFS_DISK_VERSION);
|
||||
assert(fsinfo.name_max == TWEAKED_NAME_MAX);
|
||||
assert(fsinfo.file_max == TWEAKED_FILE_MAX);
|
||||
assert(fsinfo.attr_max == TWEAKED_ATTR_MAX);
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# expanding superblock
|
||||
[cases.test_superblocks_expand]
|
||||
defines.BLOCK_CYCLES = [32, 33, 1]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# simple truncate
|
||||
[cases.test_truncate_simple]
|
||||
defines.MEDIUMSIZE = [32, 2048]
|
||||
defines.LARGESIZE = 8192
|
||||
defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
|
||||
defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
|
||||
if = 'MEDIUMSIZE < LARGESIZE'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
@@ -14,7 +15,8 @@ code = '''
|
||||
strcpy((char*)buffer, "hair");
|
||||
size_t size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
|
||||
=> lfs_min(size, LARGESIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => LARGESIZE;
|
||||
|
||||
@@ -37,8 +39,9 @@ code = '''
|
||||
|
||||
size = strlen("hair");
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||
memcmp(buffer, "hair", size) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||
|
||||
@@ -48,8 +51,9 @@ code = '''
|
||||
|
||||
# truncate and read
|
||||
[cases.test_truncate_read]
|
||||
defines.MEDIUMSIZE = [32, 2048]
|
||||
defines.LARGESIZE = 8192
|
||||
defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
|
||||
defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
|
||||
if = 'MEDIUMSIZE < LARGESIZE'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
@@ -62,7 +66,8 @@ code = '''
|
||||
strcpy((char*)buffer, "hair");
|
||||
size_t size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
|
||||
=> lfs_min(size, LARGESIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => LARGESIZE;
|
||||
|
||||
@@ -78,8 +83,9 @@ code = '''
|
||||
|
||||
size = strlen("hair");
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||
memcmp(buffer, "hair", size) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||
|
||||
@@ -92,8 +98,9 @@ code = '''
|
||||
|
||||
size = strlen("hair");
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||
memcmp(buffer, "hair", size) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||
|
||||
@@ -148,7 +155,7 @@ code = '''
|
||||
lfs_file_truncate(&lfs, &file, trunc) => 0;
|
||||
lfs_file_tell(&lfs, &file) => qsize;
|
||||
lfs_file_size(&lfs, &file) => trunc;
|
||||
|
||||
|
||||
/* Read should produce second quarter */
|
||||
lfs_file_read(&lfs, &file, rb, size) => trunc - qsize;
|
||||
memcmp(rb, wb + qsize, trunc - qsize) => 0;
|
||||
@@ -159,8 +166,9 @@ code = '''
|
||||
|
||||
# truncate and write
|
||||
[cases.test_truncate_write]
|
||||
defines.MEDIUMSIZE = [32, 2048]
|
||||
defines.LARGESIZE = 8192
|
||||
defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
|
||||
defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
|
||||
if = 'MEDIUMSIZE < LARGESIZE'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
@@ -173,7 +181,8 @@ code = '''
|
||||
strcpy((char*)buffer, "hair");
|
||||
size_t size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
|
||||
=> lfs_min(size, LARGESIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => LARGESIZE;
|
||||
|
||||
@@ -184,13 +193,16 @@ code = '''
|
||||
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
|
||||
lfs_file_size(&lfs, &file) => LARGESIZE;
|
||||
|
||||
/* truncate */
|
||||
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
|
||||
/* and write */
|
||||
strcpy((char*)buffer, "bald");
|
||||
size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
|
||||
@@ -203,8 +215,9 @@ code = '''
|
||||
|
||||
size = strlen("bald");
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||
memcmp(buffer, "bald", size) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
memcmp(buffer, "bald", lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||
|
||||
@@ -215,7 +228,7 @@ code = '''
|
||||
# truncate write under powerloss
|
||||
[cases.test_truncate_reentrant_write]
|
||||
defines.SMALLSIZE = [4, 512]
|
||||
defines.MEDIUMSIZE = [32, 1024]
|
||||
defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025]
|
||||
defines.LARGESIZE = 2048
|
||||
reentrant = true
|
||||
code = '''
|
||||
@@ -236,10 +249,11 @@ code = '''
|
||||
size == (size_t)SMALLSIZE);
|
||||
for (lfs_off_t j = 0; j < size; j += 4) {
|
||||
uint8_t buffer[1024];
|
||||
lfs_file_read(&lfs, &file, buffer, 4) => 4;
|
||||
assert(memcmp(buffer, "hair", 4) == 0 ||
|
||||
memcmp(buffer, "bald", 4) == 0 ||
|
||||
memcmp(buffer, "comb", 4) == 0);
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(4, size-j))
|
||||
=> lfs_min(4, size-j);
|
||||
assert(memcmp(buffer, "hair", lfs_min(4, size-j)) == 0 ||
|
||||
memcmp(buffer, "bald", lfs_min(4, size-j)) == 0 ||
|
||||
memcmp(buffer, "comb", lfs_min(4, size-j)) == 0);
|
||||
}
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
@@ -251,19 +265,23 @@ code = '''
|
||||
strcpy((char*)buffer, "hair");
|
||||
size_t size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
|
||||
=> lfs_min(size, LARGESIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => LARGESIZE;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
|
||||
lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0;
|
||||
lfs_file_size(&lfs, &file) => LARGESIZE;
|
||||
/* truncate */
|
||||
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
/* and write */
|
||||
strcpy((char*)buffer, "bald");
|
||||
size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
@@ -275,7 +293,8 @@ code = '''
|
||||
strcpy((char*)buffer, "comb");
|
||||
size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < SMALLSIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, SMALLSIZE-j))
|
||||
=> lfs_min(size, SMALLSIZE-j);
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => SMALLSIZE;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
@@ -429,7 +448,7 @@ code = '''
|
||||
|
||||
# noop truncate
|
||||
[cases.test_truncate_nop]
|
||||
defines.MEDIUMSIZE = [32, 2048]
|
||||
defines.MEDIUMSIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_format(&lfs, cfg) => 0;
|
||||
@@ -442,10 +461,11 @@ code = '''
|
||||
strcpy((char*)buffer, "hair");
|
||||
size_t size = strlen((char*)buffer);
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_write(&lfs, &file, buffer, size) => size;
|
||||
lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
|
||||
// this truncate should do nothing
|
||||
lfs_file_truncate(&lfs, &file, j+size) => 0;
|
||||
lfs_file_truncate(&lfs, &file, j+lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
|
||||
@@ -455,8 +475,9 @@ code = '''
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||
memcmp(buffer, "hair", size) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||
|
||||
@@ -468,8 +489,9 @@ code = '''
|
||||
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
|
||||
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
|
||||
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
|
||||
lfs_file_read(&lfs, &file, buffer, size) => size;
|
||||
memcmp(buffer, "hair", size) => 0;
|
||||
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
|
||||
=> lfs_min(size, MEDIUMSIZE-j);
|
||||
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
|
||||
}
|
||||
lfs_file_read(&lfs, &file, buffer, size) => 0;
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
|
||||
Reference in New Issue
Block a user