mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 00:38:29 +01:00
Compare commits
41 Commits
no-recursi
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40dba4a556 | ||
|
|
148e312ea3 | ||
|
|
abbfe8e92e | ||
|
|
c60c977c25 | ||
|
|
3ce64d1ac0 | ||
|
|
0ced3623d4 | ||
|
|
5451a6d503 | ||
|
|
1e038c81fc | ||
|
|
f28ac3ea7d | ||
|
|
a94fbda1cd | ||
|
|
cc025653ed | ||
|
|
bfb9bd2483 | ||
|
|
f40b854ab5 | ||
|
|
c2fa1bb7df | ||
|
|
3b62ec1c47 | ||
|
|
b898977fd8 | ||
|
|
cf274e6ec6 | ||
|
|
425dc810a5 | ||
|
|
a6f01b7d6e | ||
|
|
9c7e232086 | ||
|
|
c676bcee4c | ||
|
|
03f088b92c | ||
|
|
e955b9f65d | ||
|
|
99f58139cb | ||
|
|
5801169348 | ||
|
|
2d6f4ead13 | ||
|
|
3d1b89b41a | ||
|
|
45cefb825d | ||
|
|
bbb9e3873e | ||
|
|
c6d3c48939 | ||
|
|
2db5dc80c2 | ||
|
|
1363c9f9d4 | ||
|
|
5bc682a0d4 | ||
|
|
1877c40aac | ||
|
|
e29e7aeefa | ||
|
|
e334983767 | ||
|
|
4977fa0c0e | ||
|
|
fdda3b4aa2 | ||
|
|
487df12dde | ||
|
|
3efb8e44f3 | ||
|
|
fb2c311bb4 |
@@ -1,3 +1,4 @@
|
||||
Copyright (c) 2022, The littlefs authors.
|
||||
Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
8
SPEC.md
8
SPEC.md
@@ -233,19 +233,19 @@ Metadata tag fields:
|
||||
into a 3-bit abstract type and an 8-bit chunk field. Note that the value
|
||||
`0x000` is invalid and not assigned a type.
|
||||
|
||||
3. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into
|
||||
1. **Type1 (3-bits)** - Abstract type of the tag. Groups the tags into
|
||||
8 categories that facilitate bitmasked lookups.
|
||||
|
||||
4. **Chunk (8-bits)** - Chunk field used for various purposes by the different
|
||||
2. **Chunk (8-bits)** - Chunk field used for various purposes by the different
|
||||
abstract types. type1+chunk+id form a unique identifier for each tag in the
|
||||
metadata block.
|
||||
|
||||
5. **Id (10-bits)** - File id associated with the tag. Each file in a metadata
|
||||
3. **Id (10-bits)** - File id associated with the tag. Each file in a metadata
|
||||
block gets a unique id which is used to associate tags with that file. The
|
||||
special value `0x3ff` is used for any tags that are not associated with a
|
||||
file, such as directory and global metadata.
|
||||
|
||||
6. **Length (10-bits)** - Length of the data in bytes. The special value
|
||||
4. **Length (10-bits)** - Length of the data in bytes. The special value
|
||||
`0x3ff` indicates that this tag has been deleted.
|
||||
|
||||
## Metadata types
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Block device emulated in a file
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
@@ -10,6 +11,10 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
const struct lfs_filebd_config *bdcfg) {
|
||||
LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, "
|
||||
@@ -27,7 +32,12 @@ int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
|
||||
bd->cfg = bdcfg;
|
||||
|
||||
// open file
|
||||
#ifdef _WIN32
|
||||
bd->fd = open(path, O_RDWR | O_CREAT | O_BINARY, 0666);
|
||||
#else
|
||||
bd->fd = open(path, O_RDWR | O_CREAT, 0666);
|
||||
#endif
|
||||
|
||||
if (bd->fd < 0) {
|
||||
int err = -errno;
|
||||
LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", err);
|
||||
@@ -80,7 +90,7 @@ int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
|
||||
LFS_ASSERT(size % cfg->read_size == 0);
|
||||
LFS_ASSERT(block < cfg->block_count);
|
||||
|
||||
// zero for reproducability (in case file is truncated)
|
||||
// zero for reproducibility (in case file is truncated)
|
||||
if (bd->cfg->erase_value != -1) {
|
||||
memset(buffer, bd->cfg->erase_value, size);
|
||||
}
|
||||
@@ -193,7 +203,11 @@ int lfs_filebd_sync(const struct lfs_config *cfg) {
|
||||
LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg);
|
||||
// file sync
|
||||
lfs_filebd_t *bd = cfg->context;
|
||||
#ifdef _WIN32
|
||||
int err = FlushFileBuffers((HANDLE) _get_osfhandle(fd)) ? 0 : -1;
|
||||
#else
|
||||
int err = fsync(bd->fd);
|
||||
#endif
|
||||
if (err) {
|
||||
err = -errno;
|
||||
LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Block device emulated in a file
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Block device emulated in RAM
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
@@ -32,10 +33,12 @@ int lfs_rambd_createcfg(const struct lfs_config *cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// zero for reproducability?
|
||||
// zero for reproducibility?
|
||||
if (bd->cfg->erase_value != -1) {
|
||||
memset(bd->buffer, bd->cfg->erase_value,
|
||||
cfg->block_size * cfg->block_count);
|
||||
} else {
|
||||
memset(bd->buffer, 0, cfg->block_size * cfg->block_count);
|
||||
}
|
||||
|
||||
LFS_RAMBD_TRACE("lfs_rambd_createcfg -> %d", 0);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Block device emulated in RAM
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Testing block device, wraps filebd and rambd while providing a bunch
|
||||
* of hooks for testing littlefs in various conditions.
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Testing block device, wraps filebd and rambd while providing a bunch
|
||||
* of hooks for testing littlefs in various conditions.
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
98
lfs.c
98
lfs.c
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* The little filesystem
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
@@ -26,6 +27,7 @@ enum {
|
||||
|
||||
|
||||
/// Caching block device operations ///
|
||||
|
||||
static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) {
|
||||
// do not zero, cheaper if cache is readonly or only going to be
|
||||
// written with identical data (during relocates)
|
||||
@@ -277,22 +279,26 @@ static inline int lfs_pair_cmp(
|
||||
paira[0] == pairb[1] || paira[1] == pairb[0]);
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static inline bool lfs_pair_sync(
|
||||
const lfs_block_t paira[2],
|
||||
const lfs_block_t pairb[2]) {
|
||||
return (paira[0] == pairb[0] && paira[1] == pairb[1]) ||
|
||||
(paira[0] == pairb[1] && paira[1] == pairb[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void lfs_pair_fromle32(lfs_block_t pair[2]) {
|
||||
pair[0] = lfs_fromle32(pair[0]);
|
||||
pair[1] = lfs_fromle32(pair[1]);
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static inline void lfs_pair_tole32(lfs_block_t pair[2]) {
|
||||
pair[0] = lfs_tole32(pair[0]);
|
||||
pair[1] = lfs_tole32(pair[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// operations on 32-bit entry tags
|
||||
typedef uint32_t lfs_tag_t;
|
||||
@@ -374,6 +380,7 @@ static inline bool lfs_gstate_iszero(const lfs_gstate_t *a) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static inline bool lfs_gstate_hasorphans(const lfs_gstate_t *a) {
|
||||
return lfs_tag_size(a->tag);
|
||||
}
|
||||
@@ -385,6 +392,7 @@ 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_hasmovehere(const lfs_gstate_t *a,
|
||||
const lfs_block_t *pair) {
|
||||
@@ -397,11 +405,13 @@ static inline void lfs_gstate_fromle32(lfs_gstate_t *a) {
|
||||
a->pair[1] = lfs_fromle32(a->pair[1]);
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static inline void lfs_gstate_tole32(lfs_gstate_t *a) {
|
||||
a->tag = lfs_tole32(a->tag);
|
||||
a->pair[0] = lfs_tole32(a->pair[0]);
|
||||
a->pair[1] = lfs_tole32(a->pair[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// other endianness operations
|
||||
static void lfs_ctz_fromle32(struct lfs_ctz *ctz) {
|
||||
@@ -425,6 +435,7 @@ static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) {
|
||||
superblock->attr_max = lfs_fromle32(superblock->attr_max);
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
|
||||
superblock->version = lfs_tole32(superblock->version);
|
||||
superblock->block_size = lfs_tole32(superblock->block_size);
|
||||
@@ -433,6 +444,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
|
||||
superblock->file_max = lfs_tole32(superblock->file_max);
|
||||
superblock->attr_max = lfs_tole32(superblock->attr_max);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_NO_ASSERT
|
||||
static bool lfs_mlist_isopen(struct lfs_mlist *head,
|
||||
@@ -755,11 +767,10 @@ static int lfs_dir_traverse_filter(void *p,
|
||||
// maximum recursive depth of lfs_dir_traverse, the deepest call:
|
||||
//
|
||||
// traverse with commit
|
||||
// '-> traverse with filter
|
||||
// '-> traverse with move
|
||||
// ' traverse with filter
|
||||
// '-> traverse with filter
|
||||
//
|
||||
#define LFS_DIR_TRAVERSE_DEPTH 4
|
||||
#define LFS_DIR_TRAVERSE_DEPTH 3
|
||||
|
||||
struct lfs_dir_traverse {
|
||||
const lfs_mdir_t *dir;
|
||||
@@ -881,6 +892,26 @@ popped:
|
||||
if (lfs_tag_type3(tag) == LFS_FROM_NOOP) {
|
||||
// do nothing
|
||||
} else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) {
|
||||
// Without this condition, lfs_dir_traverse can exhibit an
|
||||
// extremely expensive O(n^3) of nested loops when renaming.
|
||||
// This happens because lfs_dir_traverse tries to filter tags by
|
||||
// the tags in the source directory, triggering a second
|
||||
// lfs_dir_traverse with its own filter operation.
|
||||
//
|
||||
// traverse with commit
|
||||
// '-> traverse with filter
|
||||
// '-> traverse with move
|
||||
// '-> traverse with filter
|
||||
//
|
||||
// However we don't actually care about filtering the second set of
|
||||
// tags, since duplicate tags have no effect when filtering.
|
||||
//
|
||||
// This check skips this unnecessary recursive filtering explicitly,
|
||||
// reducing this runtime from O(n^3) to O(n^2).
|
||||
if (cb == lfs_dir_traverse_filter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// recurse into move
|
||||
stack[sp] = (struct lfs_dir_traverse){
|
||||
.dir = dir,
|
||||
@@ -1576,7 +1607,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
|
||||
}
|
||||
}
|
||||
|
||||
// zero for reproducability in case initial block is unreadable
|
||||
// zero for reproducibility in case initial block is unreadable
|
||||
dir->rev = 0;
|
||||
|
||||
// rather than clobbering one of the blocks we just pretend
|
||||
@@ -1636,7 +1667,6 @@ static int lfs_dir_split(lfs_t *lfs,
|
||||
lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
|
||||
lfs_mdir_t *source, uint16_t split, uint16_t end) {
|
||||
// create tail metadata pair
|
||||
lfs_alloc_ack(lfs);
|
||||
lfs_mdir_t tail;
|
||||
int err = lfs_dir_alloc(lfs, &tail);
|
||||
if (err) {
|
||||
@@ -1934,6 +1964,7 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
// performance
|
||||
LFS_WARN("Unable to split {0x%"PRIx32", 0x%"PRIx32"}",
|
||||
dir->pair[0], dir->pair[1]);
|
||||
break;
|
||||
} else {
|
||||
end = split;
|
||||
}
|
||||
@@ -2858,8 +2889,11 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
||||
{LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL},
|
||||
{LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path},
|
||||
{LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL}));
|
||||
|
||||
// it may happen that the file name doesn't fit in the metadata blocks, e.g., a 256 byte file name will
|
||||
// not fit in a 128 byte block.
|
||||
err = (err == LFS_ERR_NOSPC) ? LFS_ERR_NAMETOOLONG : err;
|
||||
if (err) {
|
||||
err = LFS_ERR_NAMETOOLONG;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -3075,7 +3109,6 @@ static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
|
||||
if (file->flags & LFS_F_READING) {
|
||||
if (!(file->flags & LFS_F_INLINE)) {
|
||||
@@ -3084,6 +3117,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
|
||||
file->flags &= ~LFS_F_READING;
|
||||
}
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
if (file->flags & LFS_F_WRITING) {
|
||||
lfs_off_t pos = file->pos;
|
||||
|
||||
@@ -3150,10 +3184,10 @@ relocate:
|
||||
|
||||
file->pos = pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_READONLY
|
||||
static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
||||
@@ -3427,9 +3461,18 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
||||
if (whence == LFS_SEEK_SET) {
|
||||
npos = off;
|
||||
} else if (whence == LFS_SEEK_CUR) {
|
||||
if ((lfs_soff_t)file->pos + off < 0) {
|
||||
return LFS_ERR_INVAL;
|
||||
} else {
|
||||
npos = file->pos + off;
|
||||
}
|
||||
} else if (whence == LFS_SEEK_END) {
|
||||
npos = lfs_file_rawsize(lfs, file) + off;
|
||||
lfs_soff_t res = lfs_file_rawsize(lfs, file) + off;
|
||||
if (res < 0) {
|
||||
return LFS_ERR_INVAL;
|
||||
} else {
|
||||
npos = res;
|
||||
}
|
||||
}
|
||||
|
||||
if (npos > lfs->file_max) {
|
||||
@@ -3442,13 +3485,32 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
||||
return npos;
|
||||
}
|
||||
|
||||
// if we're only reading and our new offset is still in the file's cache
|
||||
// we can avoid flushing and needing to reread the data
|
||||
if (
|
||||
#ifndef LFS_READONLY
|
||||
!(file->flags & LFS_F_WRITING)
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
) {
|
||||
int oindex = lfs_ctz_index(lfs, &(lfs_off_t){file->pos});
|
||||
lfs_off_t noff = npos;
|
||||
int nindex = lfs_ctz_index(lfs, &noff);
|
||||
if (oindex == nindex
|
||||
&& noff >= file->cache.off
|
||||
&& noff < file->cache.off + file->cache.size) {
|
||||
file->pos = npos;
|
||||
file->off = noff;
|
||||
return npos;
|
||||
}
|
||||
}
|
||||
|
||||
// write out everything beforehand, may be noop if rdonly
|
||||
int err = lfs_file_flush(lfs, file);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
// update pos
|
||||
file->pos = npos;
|
||||
@@ -4123,6 +4185,20 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
|
||||
lfs->attr_max = superblock.attr_max;
|
||||
}
|
||||
|
||||
if (superblock.block_count != lfs->cfg->block_count) {
|
||||
LFS_ERROR("Invalid block count (%"PRIu32" != %"PRIu32")",
|
||||
superblock.block_count, lfs->cfg->block_count);
|
||||
err = LFS_ERR_INVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (superblock.block_size != lfs->cfg->block_size) {
|
||||
LFS_ERROR("Invalid block size (%"PRIu32" != %"PRIu32")",
|
||||
superblock.block_count, lfs->cfg->block_count);
|
||||
err = LFS_ERR_INVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// has gstate?
|
||||
@@ -5393,6 +5469,7 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LFS_NO_MALLOC
|
||||
int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) {
|
||||
int err = LFS_LOCK(lfs->cfg);
|
||||
if (err) {
|
||||
@@ -5408,6 +5485,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) {
|
||||
LFS_UNLOCK(lfs->cfg);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
||||
const char *path, int flags,
|
||||
|
||||
44
lfs.h
44
lfs.h
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* The little filesystem
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
@@ -22,7 +23,7 @@ extern "C"
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS_VERSION 0x00020004
|
||||
#define LFS_VERSION 0x00020005
|
||||
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
|
||||
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
|
||||
|
||||
@@ -159,49 +160,49 @@ struct lfs_config {
|
||||
// information to the block device operations
|
||||
void *context;
|
||||
|
||||
// Read a region in a block. Negative error codes are propogated
|
||||
// Read a region in a block. Negative error codes are propagated
|
||||
// to the user.
|
||||
int (*read)(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated to the user.
|
||||
// been erased. Negative error codes are propagated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*prog)(const struct lfs_config *c, lfs_block_t block,
|
||||
lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated to the user.
|
||||
// are propagated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*erase)(const struct lfs_config *c, lfs_block_t block);
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
// are propagated to the user.
|
||||
int (*sync)(const struct lfs_config *c);
|
||||
|
||||
#ifdef LFS_THREADSAFE
|
||||
// Lock the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
// are propagated to the user.
|
||||
int (*lock)(const struct lfs_config *c);
|
||||
|
||||
// Unlock the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
// are propagated to the user.
|
||||
int (*unlock)(const struct lfs_config *c);
|
||||
#endif
|
||||
|
||||
// Minimum size of a block read. All read operations will be a
|
||||
// Minimum size of a block read in bytes. All read operations will be a
|
||||
// multiple of this value.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a block program. All program operations will be a
|
||||
// multiple of this value.
|
||||
// Minimum size of a block program in bytes. All program operations will be
|
||||
// a multiple of this value.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erasable block. This does not impact ram consumption and
|
||||
// may be larger than the physical erase size. However, non-inlined files
|
||||
// take up at minimum one block. Must be a multiple of the read
|
||||
// and program sizes.
|
||||
// Size of an erasable block in bytes. This does not impact ram consumption
|
||||
// and may be larger than the physical erase size. However, non-inlined
|
||||
// files take up at minimum one block. Must be a multiple of the read and
|
||||
// program sizes.
|
||||
lfs_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device.
|
||||
@@ -215,11 +216,11 @@ struct lfs_config {
|
||||
// Set to -1 to disable block-level wear-leveling.
|
||||
int32_t block_cycles;
|
||||
|
||||
// Size of block caches. Each cache buffers a portion of a block in RAM.
|
||||
// The littlefs needs a read cache, a program cache, and one additional
|
||||
// Size of block caches in bytes. Each cache buffers a portion of a block in
|
||||
// RAM. The littlefs needs a read cache, a program cache, and one additional
|
||||
// cache per file. Larger caches can improve performance by storing more
|
||||
// data and reducing the number of disk accesses. Must be a multiple of
|
||||
// the read and program sizes, and a factor of the block size.
|
||||
// data and reducing the number of disk accesses. Must be a multiple of the
|
||||
// read and program sizes, and a factor of the block size.
|
||||
lfs_size_t cache_size;
|
||||
|
||||
// Size of the lookahead buffer in bytes. A larger lookahead buffer
|
||||
@@ -485,7 +486,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
|
||||
// Returns the size of the attribute, or a negative error code on failure.
|
||||
// Note, the returned size is the size of the attribute on disk, irrespective
|
||||
// of the size of the buffer. This can be used to dynamically allocate a buffer
|
||||
// or check for existance.
|
||||
// or check for existence.
|
||||
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
|
||||
uint8_t type, void *buffer, lfs_size_t size);
|
||||
|
||||
@@ -513,6 +514,7 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
|
||||
|
||||
/// File operations ///
|
||||
|
||||
#ifndef LFS_NO_MALLOC
|
||||
// Open a file
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
@@ -522,6 +524,10 @@ int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
|
||||
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
|
||||
const char *path, int flags);
|
||||
|
||||
// if LFS_NO_MALLOC is defined, lfs_file_open() will fail with LFS_ERR_NOMEM
|
||||
// thus use lfs_file_opencfg() with config.buffer set.
|
||||
#endif
|
||||
|
||||
// Open a file with extra configuration
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* lfs util functions
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* lfs utility functions
|
||||
*
|
||||
* Copyright (c) 2022, The littlefs authors.
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@@ -565,7 +565,7 @@ class TestSuite:
|
||||
path=self.path))
|
||||
mk.write('\n')
|
||||
|
||||
# add truely global defines globally
|
||||
# add truly global defines globally
|
||||
for k, v in sorted(self.defines.items()):
|
||||
mk.write('%s.test: override CFLAGS += -D%s=%r\n'
|
||||
% (self.path, k, v))
|
||||
@@ -656,7 +656,7 @@ def main(**args):
|
||||
for path in glob.glob(testpath):
|
||||
suites.append(TestSuite(path, classes, defines, filter, **args))
|
||||
|
||||
# sort for reproducability
|
||||
# sort for reproducibility
|
||||
suites = sorted(suites)
|
||||
|
||||
# generate permutations
|
||||
|
||||
Reference in New Issue
Block a user