Compare commits

...

35 Commits

Author SHA1 Message Date
Christopher Haster
2cd895dbba Fixed incorrect documentation in test.py
The argparse documented an outdated format, and was off by 1.

Found by sender6
2020-12-13 10:26:46 -06:00
Christopher Haster
1a59954ec6 Merge pull request #495 from littlefs-project/devel
Minor release: v2.3
2020-12-07 20:50:31 -06:00
Christopher Haster
6a7012774d Renamed internal lfs_*raw -> lfs_raw* functions
- Prefixing with raw is slightly more readable, follows
  common-prefix rule
- Matches existing raw prefixes in testbd
2020-12-06 00:26:24 -06:00
Christopher Haster
288a5cbc8d Bumped minor version to v2.3 2020-12-04 01:31:27 -06:00
Christopher Haster
5783eea0de Merge pull request #490 from littlefs-project/fix-alloc-eviction
Fix allocation-eviction issue when erase state is multiple of block_cycles+1
2020-12-04 00:49:09 -06:00
Christopher Haster
2bb523421e Moved lfs_mlist_isopen checks into the API wrappers
This indirectly solves an issue with lfs_file_rawclose asserting
when lfs_file_opencfg errors since appending to the mlist occurs
after open. It also may speed up some of the internal operations such as
the lfs_file_write used to resolve unflushed data.

The idea behind adopting mlist over flags is that realistically it's
unlikely for the user to open a significant number of files (enough for
big O to kick in). That being said, moving the mlist asserts into the
API wrappers does protect some of the internal operations from scaling
based on the number of open files.
2020-12-04 00:42:32 -06:00
Noah Gorny
7388b2938a Deprecate LFS_F_OPENED and use lfs_mlist_isused instead
Instead of additional flag, we can just go through the mlist.
2020-12-04 00:26:19 -06:00
Christopher Haster
ce425a56c3 Merge pull request #470 from renesas/SWFLEX-1517-littlefs-thread-safe-option
Add thread safe wrappers
2020-12-03 23:47:32 -06:00
Christopher Haster
a99a93fb27 Added thread-safe build+size reporting to CI 2020-12-03 23:46:59 -06:00
Christopher Haster
45afded784 Moved LFS_TRACE calls to API wrapper functions
This removes quite a bit of extra code needed to entertwine the
LFS_TRACE calls into the original funcions.

Also changed temporary return type to match API declaration where
necessary.
2020-12-03 23:46:59 -06:00
Christopher Haster
00a9ba7826 Tweaked thread-safe implementation
- Stayed on non-system include for lfs_util.h for now
- Named internal functions "lfs_functionraw"
- Merged lfs_fs_traverseraw
- Added LFS_LOCK/UNLOCK macros
- Changed LFS_THREADSAFE from 1/0 to defined/undefined to
  match LFS_READONLY
2020-12-03 23:46:59 -06:00
Bill Gesner
fc6988c7c3 make raw functions static. formatting tweaks 2020-12-03 23:46:54 -06:00
Bill Gesner
d0f055d321 Squash of thread-safe PR cleanup
- expand functions
- add comment
- rename functions
- fix locking issue in format and mount
- use global include
- fix ac6 linker issue
- use the global config file
- address review comments
- minor cleanup
- minor cleanup
- review comments
2020-12-03 23:41:01 -06:00
Christopher Haster
b9fa33f9bc Merge pull request #480 from maximevince/master
Add LFS_READONLY define, to allow smaller builds providing read-only mode
2020-12-03 23:06:00 -06:00
Christopher Haster
2efebf8e9b Added read-only build+size reporting to CI 2020-12-03 23:04:48 -06:00
Maxime Vincent
754b4c3cda Squash of LFS_READONLY cleanup
- undef unavailable function declarations altogether
- even less code, assert on write attempts
- remove LFS_O_WRONLY and other flags when compiling with LFS_READONLY
- do not annotate #endif, as requested
- move ifdef before comments blocks, rework dangling opening bracket
- ifdef file flags that are not needed in read-only mode
- slight refactor
- ifdef LFS_F_ERRED out as well
2020-12-03 23:03:29 -06:00
Christopher Haster
584eb26efc Merge pull request #443 from NoahGorny/add-already-opened-assert
Assert that the file isnt open in lfs_file_opencfg
2020-12-03 22:43:10 -06:00
Noah Gorny
008ebc37df Add lfs_mlist_append/remove helper 2020-12-03 22:42:39 -06:00
Christopher Haster
66272067ab Merge pull request #395 from gmpy/improve-write-performance
lfs_bd_cmp() compares more bytes at one time
2020-12-03 22:34:47 -06:00
Christopher Haster
e273a82679 Merge pull request #487 from littlefs-project/fix-alloc-reset-modulus
Fix several wear-leveling issues found in lfs_alloc_reset
2020-12-03 22:33:47 -06:00
Christopher Haster
1dc6ae94b9 Merge pull request #486 from littlefs-project/fix-assert
Fix assert
2020-12-03 22:32:56 -06:00
Christopher Haster
817ef02d24 Merge pull request #412 from jrast/patch-3
Added littlefs-python to the related projects section
2020-12-03 22:32:04 -06:00
Christopher Haster
b8dcf10974 Changed lfs_dir_alloc to maximize block cycles for new metadata pairs
Previously we only bumped the revision count if an eviction would occur
immediately (and possibly corrupt littlefs). This works, but does risk
an unoptimal superblock size if an almost-exhausted superblock was
allocated during lfs_format.

As pointed out by tim-nordell-nimbelink, we can align the revision count
to maximize the number of block cycles without breaking the existing
requirements of increasing revision counts.

As an added benefit, littlefs's wear-leveling should behave more
consistently after this change.
2020-11-28 22:46:11 -06:00
Christopher Haster
0aba71d0d6 Fixed single unchecked bit during commit verification
This bug was exposed by the bad-block tests due to changes to block
allocation, but could have been hit before these changes.

In flash, when blocks fail, they don't fail in a predictable manner. To
account for this, the bad-block tests check a number of failure
behaviors. The interesting one here is "LFS_TESTBD_BADBLOCK_ERASENOOP",
in which bad blocks can not be erased or programmed, and are stuck with
the data written at the time the blocks go bad.

This is actually a pretty realistic failure behavior, since flash needs a
large voltage to force the electrons of the floating gates. Though
realistically, such a failure would like corrupt the data a bit, not leave the
underlying data perfectly intact.

LFS_TESTBD_BADBLOCK_ERASENOOP is rather interesting to test for because it
means bad blocks can end up with perfectly valid CRCs after a failed write,
confusing littlefs.

---

In this case, we had the perfect series of operations such that a test
was repeatedly writing the same sequence of metadata commits to the same
block, which eventually goes bad, leaving the block stuck with metadata
that occurs later in the sequence.

What this means is that after the first commit, the metadata block
contained both the first and second commits, even though the loop in the
test hadn't reached that point yet.

expected       actual
.----------.  .----------.
| commit 1 |  | commit 1 |
| crc 1    |  | crc 1    |
|          |  | commit 2 <-- (from previous iteration)
|          |  | crc 2    |
'----------'  '----------'

To protect against this, littlefs normally compares the written CRC
against the expected CRC, but because this was the exact same data that
it was going to write, this CRCs end up the same.

Ah! But doesn't littlefs also encode the state of the next page to keep
track of if the next page has been erased or not? Wouldn't that change
between iterations?

It does! In a single bit in the CRC-tag. But thanks to some incorrect
logic attempting to avoid an extra condition in the loop for writing out
padding commits, the CRC that littlefs checked against was the CRC
immediately before we include the "is-next-page-erased" bit.

Changing the verification check to use the same CRC as what is used to
verify commits on fetch solves this problem.
2020-11-22 15:07:16 -06:00
Christopher Haster
0ea2871e24 Fixed typo in scripts/readtree.py
Not sure how this went unnoticed, I guess this is the first bug that
needed in-depth inspection after the a last-minute argument cleanup
in the debug scripts.
2020-11-22 15:05:22 -06:00
Christopher Haster
d04c1392c0 Fixed allocation-eviction issue when erase state is multiple of block_cycles+1
This rather interesting corner-case arises in lfs_dir_alloc anytime the
uninitialized revision count happens to be a multiple of block_cycles+1.

For example, the source of the bug found by tim-nordell-nimbelink:

rev = 2742492087
block_cycles = 100

2742492087 % (100+1) = 0

The reason for this weird block_cycles+1 case is due to a fix for a
previous bug in fe957de. To avoid aliasing, which would cause metadata
pairs to wear unevenly, block_cycles incremented to the next odd number.

Normally, littlefs tweaks the revision count of blocks during
lfs_dir_alloc in order to make sure evictions can't happen on the first
compact. Otherwise, higher-level logic such as lfs_format would break.

However, this wasn't updated with the aliasing fix in fe957de, so
lfs_dir_alloc was only rounding the revision count to the nearest even
number.

The current fix is to change the logic in lfs_dir_alloc to explicitly
check for the eviction condition and increment if eviction would occur.

Found by tim-nordell-nimbelink
2020-11-22 00:40:58 -06:00
Christopher Haster
f215027fd4 Switched to CRC as seed collection function instead of xor
As noted by gtaska, we are sitting on a better hash-combining function
than xor: CRC. Previous issues with xor were solvable, but relying on
xor for this isn't really worth the risk when we already have a CRC
function readily available.

To quote a study found by gtaska:

https://michiel.buddingh.eu/distribution-of-hash-values

> CRC32 seems to score really well, but its graph is skewed by the results
> of Dataset 5 (binary numbers), which may or may not be too synthetic to
> be considered a fair benchmark. But even if you substract the results
> from that test, it does not fare significantly worse than other,
> cryptographic hash functions.
2020-11-20 00:38:41 -06:00
Christopher Haster
1ae4b36f2a Removed unnecessary randomization of offsets in lfs_alloc_reset
On first read, randomizing the allocators offset may seem appropriate
for lfs_alloc_reset. However, it ends up using the filesystem-fed
pseudorandom seed in situations it wasn't designed for.

As noted by gtaska, the combination of using xors for feeding the seed
and multiple traverses of the same CRCs can cause the seed to flip to
zeros with concerning frequency.

Removed the randomization from lfs_alloc_reset, leaving it in only
lfs_mount.

Found by gtaska
2020-11-20 00:18:13 -06:00
Christopher Haster
480cdd9f81 Fixed incorrect modulus in lfs_alloc_reset
Modulus of the offset by block_size was clearly a typo, and should be
block_count. Interesting to note that later moduluses during alloc
calculations prevents this from breaking anything, but as gtaska notes it
could skew the wear-leveling distribution.

Found by guiserle and gtaska
2020-11-20 00:02:19 -06:00
Noah Gorny
6303558aee Use LFS_O_RDWR instead of magic number in lfs_file_* asserts 2020-11-19 01:51:39 +02:00
Noah Gorny
4bd653dd00 Assert that file/dir struct is not reused in lfs_file_opencfg/lfs_dir_open 2020-11-19 01:51:39 +02:00
Maxime Vincent
8e6826c4e2 Add LFS_READYONLY define, to allow smaller builds providing read-only mode 2020-10-28 16:09:13 +01:00
Shiven Gupta
87a2cb0e41 Fix assert 2020-08-18 17:36:14 -04:00
Jürg Rast
6d0ec5e851 Added littlefs-python to the related projects section
As introduced in #297, I created a python wrapper for littlefs. The wrapper supports two API's: A C-like API which is the same as in C and a more pythonic API which is easier to use if you are more the python guy. The wrapper is built with littlefs 2.2.1 at the moment.
2020-04-13 21:33:30 +02:00
WeiXiong Liao
64f70f51b0 lfs_bd_cmp() compares more bytes at one time
It's very slowly to compare one byte at one time. Here are the
performance I get from 128M spinand with NFTL by sequential writing.

| file size | buffer size  | write speed  |
| 10 MB     | 0   B        | 3206.01 KB/s |
| 10 MB     | 1   B        | 2434.04 KB/s |
| 10 MB     | 2   B        | 2685.78 KB/s |
| 10 MB     | 4   B        | 2857.94 KB/s |
| 10 MB     | 8   B        | 3060.68 KB/s |
| 10 MB     | 16  B        | 3155.30 KB/s |
| 10 MB     | 64  B        | 3193.68 KB/s |
| 10 MB     | 128 B        | 3230.62 KB/s |
| 10 MB     | 256 B        | 3153.03 KB/s |

| 70 MB     | 0   B        | 2258.87 KB/s |
| 70 MB     | 1   B        | 1827.83 KB/s |
| 70 MB     | 2   B        | 1962.29 KB/s |
| 70 MB     | 4   B        | 2074.01 KB/s |
| 70 MB     | 8   B        | 2147.03 KB/s |
| 70 MB     | 64  B        | 2179.92 KB/s |
| 70 MB     | 256 B        | 2179.96 KB/s |

The 0 Byte size means no validation and the 1 Byte size is how
littlefs do before. Based on the above table and to save memory,
comparing 8 bytes at one time is more wonderful.

Signed-off-by: WeiXiong Liao <liaoweixiong@allwinnertech.com>
2020-03-13 15:23:20 +08:00
8 changed files with 908 additions and 596 deletions

View File

@@ -208,6 +208,38 @@ jobs:
script:
- make test TFLAGS+="-k --valgrind"
# test compilation in read-only mode
- stage: test
env:
- NAME=littlefs-readonly
- CC="arm-linux-gnueabi-gcc --static -mthumb"
- CFLAGS="-Werror -DLFS_READONLY"
if: branch !~ -prefix$
install:
- *install-common
- sudo apt-get install
gcc-arm-linux-gnueabi
libc6-dev-armel-cross
- arm-linux-gnueabi-gcc --version
# report-size will compile littlefs and report the size
script: [*report-size]
# test compilation in thread-safe mode
- stage: test
env:
- NAME=littlefs-threadsafe
- CC="arm-linux-gnueabi-gcc --static -mthumb"
- CFLAGS="-Werror -DLFS_THREADSAFE"
if: branch !~ -prefix$
install:
- *install-common
- sudo apt-get install
gcc-arm-linux-gnueabi
libc6-dev-armel-cross
- arm-linux-gnueabi-gcc --version
# report-size will compile littlefs and report the size
script: [*report-size]
# self-host with littlefs-fuse for fuzz test
- stage: test
env:

View File

@@ -221,6 +221,11 @@ License Identifiers that are here available: http://spdx.org/licenses/
- [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would
want this, but it is handy for demos. You can see it in action
[here][littlefs-js-demo].
- [littlefs-python] - A Python wrapper for littlefs. The project allows you
to create images of the filesystem on your PC. Check if littlefs will fit
your needs, create images for a later download to the target memory or
inspect the content of a binary image of the target memory.
- [mklfs] - A command line tool built by the [Lua RTOS] guys for making
littlefs images from a host PC. Supports Windows, Mac OS, and Linux.
@@ -250,3 +255,4 @@ License Identifiers that are here available: http://spdx.org/licenses/
[LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html
[SPIFFS]: https://github.com/pellepl/spiffs
[Dhara]: https://github.com/dlbeer/dhara
[littlefs-python]: https://pypi.org/project/littlefs-python/

View File

@@ -207,7 +207,7 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// sync to make sure we persist the last changes
assert(lfs_testbd_rawsync(cfg) == 0);
LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0);
// simulate power loss
exit(33);
}
@@ -254,7 +254,7 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// sync to make sure we persist the last changes
assert(lfs_testbd_rawsync(cfg) == 0);
LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0);
// simulate power loss
exit(33);
}

1248
lfs.c

File diff suppressed because it is too large Load Diff

203
lfs.h
View File

@@ -22,7 +22,7 @@ extern "C"
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00020002
#define LFS_VERSION 0x00020003
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
@@ -54,7 +54,7 @@ typedef uint32_t lfs_block_t;
// Maximum size of a file in bytes, may be redefined to limit to support other
// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
// functions _lfs_file_seek, _lfs_file_size, and _lfs_file_tell will return
// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS_FILE_MAX
@@ -85,9 +85,6 @@ enum lfs_error {
LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NOATTR = -61, // No data/attr available
LFS_ERR_NAMETOOLONG = -36, // File name too long
#if LFS_THREAD_SAFE
LFS_ERR_LOCK = -23, // Failed to aquire lock
#endif
};
// File types
@@ -127,20 +124,25 @@ enum lfs_type {
enum lfs_open_flags {
// open flags
LFS_O_RDONLY = 1, // Open a file as read only
#ifndef LFS_READONLY
LFS_O_WRONLY = 2, // Open a file as write only
LFS_O_RDWR = 3, // Open a file as read and write
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
LFS_O_EXCL = 0x0200, // Fail if a file already exists
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS_O_APPEND = 0x0800, // Move to end of file on every write
#endif
// internally used flags
#ifndef LFS_READONLY
LFS_F_DIRTY = 0x010000, // File does not match storage
LFS_F_WRITING = 0x020000, // File has been written since last flush
#endif
LFS_F_READING = 0x040000, // File has been read since last flush
LFS_F_ERRED = 0x080000, // An error occured during write
#ifndef LFS_READONLY
LFS_F_ERRED = 0x080000, // An error occurred during write
#endif
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
LFS_F_OPENED = 0x200000, // File has been opened
};
// File seek flags
@@ -178,7 +180,7 @@ struct lfs_config {
// are propogated to the user.
int (*sync)(const struct lfs_config *c);
#if LFS_THREAD_SAFE
#ifdef LFS_THREADSAFE
// Lock the underlying block device. Negative error codes
// are propogated to the user.
int (*lock)(const struct lfs_config *c);
@@ -186,7 +188,7 @@ struct lfs_config {
// Unlock the underlying block device. Negative error codes
// are propogated to the user.
int (*unlock)(const struct lfs_config *c);
#endif
#endif
// Minimum size of a block read. All read operations will be a
// multiple of this value.
@@ -413,6 +415,7 @@ typedef struct lfs {
/// Filesystem functions ///
#ifndef LFS_READONLY
// Format a block device with the littlefs
//
// Requires a littlefs object and config struct. This clobbers the littlefs
@@ -420,7 +423,8 @@ typedef struct lfs {
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int _lfs_format(lfs_t *lfs, const struct lfs_config *config);
int lfs_format(lfs_t *lfs, const struct lfs_config *config);
#endif
// Mounts a littlefs
//
@@ -430,35 +434,39 @@ int _lfs_format(lfs_t *lfs, const struct lfs_config *config);
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int _lfs_mount(lfs_t *lfs, const struct lfs_config *config);
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
// Unmounts a littlefs
//
// Does nothing besides releasing any allocated resources.
// Returns a negative error code on failure.
int _lfs_unmount(lfs_t *lfs);
int lfs_unmount(lfs_t *lfs);
/// General operations ///
#ifndef LFS_READONLY
// Removes a file or directory
//
// If removing a directory, the directory must be empty.
// Returns a negative error code on failure.
int _lfs_remove(lfs_t *lfs, const char *path);
int lfs_remove(lfs_t *lfs, const char *path);
#endif
#ifndef LFS_READONLY
// Rename or move a file or directory
//
// If the destination exists, it must match the source in type.
// If the destination is a directory, the directory must be empty.
//
// Returns a negative error code on failure.
int _lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
#endif
// Find info about a file or directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a negative error code on failure.
int _lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// Get a custom attribute
//
@@ -472,9 +480,10 @@ int _lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// 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.
lfs_ssize_t _lfs_getattr(lfs_t *lfs, const char *path,
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size);
#ifndef LFS_READONLY
// Set custom attributes
//
// Custom attributes are uniquely identified by an 8-bit type and limited
@@ -482,15 +491,18 @@ lfs_ssize_t _lfs_getattr(lfs_t *lfs, const char *path,
// implicitly created.
//
// Returns a negative error code on failure.
int _lfs_setattr(lfs_t *lfs, const char *path,
int lfs_setattr(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size);
#endif
#ifndef LFS_READONLY
// Removes a custom attribute
//
// If an attribute is not found, nothing happens.
//
// Returns a negative error code on failure.
int _lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
#endif
/// File operations ///
@@ -501,7 +513,7 @@ int _lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
// are values from the enum lfs_open_flags that are bitwise-ored together.
//
// Returns a negative error code on failure.
int _lfs_file_open(lfs_t *lfs, lfs_file_t *file,
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags);
// Open a file with extra configuration
@@ -514,7 +526,7 @@ int _lfs_file_open(lfs_t *lfs, lfs_file_t *file,
// config struct must be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int _lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags,
const struct lfs_file_config *config);
@@ -524,86 +536,92 @@ int _lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
// sync had been called and releases any allocated resources.
//
// Returns a negative error code on failure.
int _lfs_file_close(lfs_t *lfs, lfs_file_t *file);
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
// Synchronize a file on storage
//
// Any pending writes are written out to storage.
// Returns a negative error code on failure.
int _lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
// Read data from file
//
// Takes a buffer and size indicating where to store the read data.
// Returns the number of bytes read, or a negative error code on failure.
lfs_ssize_t _lfs_file_read(lfs_t *lfs, lfs_file_t *file,
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size);
#ifndef LFS_READONLY
// Write data to file
//
// Takes a buffer and size indicating the data to write. The file will not
// actually be updated on the storage until either sync or close is called.
//
// Returns the number of bytes written, or a negative error code on failure.
lfs_ssize_t _lfs_file_write(lfs_t *lfs, lfs_file_t *file,
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size);
#endif
// Change the position of the file
//
// The change in position is determined by the offset and whence flag.
// Returns the new position of the file, or a negative error code on failure.
lfs_soff_t _lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
lfs_soff_t off, int whence);
#ifndef LFS_READONLY
// Truncates the size of the file to the specified size
//
// Returns a negative error code on failure.
int _lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
#endif
// Return the position of the file
//
// Equivalent to _lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
// Returns the position of the file, or a negative error code on failure.
lfs_soff_t _lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
// Change the position of the file to the beginning of the file
//
// Equivalent to _lfs_file_seek(lfs, file, 0, LFS_SEEK_SET)
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET)
// Returns a negative error code on failure.
int _lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
// Return the size of the file
//
// Similar to _lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
// Returns the size of the file, or a negative error code on failure.
lfs_soff_t _lfs_file_size(lfs_t *lfs, lfs_file_t *file);
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
/// Directory operations ///
#ifndef LFS_READONLY
// Create a directory
//
// Returns a negative error code on failure.
int _lfs_mkdir(lfs_t *lfs, const char *path);
int lfs_mkdir(lfs_t *lfs, const char *path);
#endif
// Open a directory
//
// Once open a directory can be used with read to iterate over files.
// Returns a negative error code on failure.
int _lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
// Close a directory
//
// Releases any allocated resources.
// Returns a negative error code on failure.
int _lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
// Read an entry in the directory
//
// Fills out the info structure, based on the specified file or directory.
// Returns a positive value on success, 0 at the end of directory,
// or a negative error code on failure.
int _lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
// Change the position of the directory
//
@@ -611,7 +629,7 @@ int _lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
// an absolute offset in the directory seek.
//
// Returns a negative error code on failure.
int _lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
// Return the position of the directory
//
@@ -619,12 +637,12 @@ int _lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
// sense, but does indicate the current position in the directory iteration.
//
// Returns the position of the directory, or a negative error code on failure.
lfs_soff_t _lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
// Change the position of the directory to the beginning of the directory
//
// Returns a negative error code on failure.
int _lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
/// Filesystem-level filesystem operations
@@ -635,7 +653,7 @@ int _lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
// size may be larger than the filesystem actually is.
//
// Returns the number of allocated blocks, or a negative error code on failure.
lfs_ssize_t _lfs_fs_size(lfs_t *lfs);
lfs_ssize_t lfs_fs_size(lfs_t *lfs);
// Traverse through all blocks in use by the filesystem
//
@@ -644,12 +662,13 @@ lfs_ssize_t _lfs_fs_size(lfs_t *lfs);
// blocks are in use or how much of the storage is available.
//
// Returns a negative error code on failure.
int _lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
#ifndef LFS_READONLY
#ifdef LFS_MIGRATE
// Attempts to migrate a previous version of littlefs
//
// Behaves similarly to the _lfs_format function. Attempts to mount
// Behaves similarly to the lfs_format function. Attempts to mount
// the previous version of littlefs and update the filesystem so it can be
// mounted with the current version of littlefs.
//
@@ -658,106 +677,8 @@ int _lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
// be zeroed for defaults and backwards compatibility.
//
// Returns a negative error code on failure.
int _lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg);
int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg);
#endif
#if LFS_THREAD_SAFE
int _ts_lfs_format(lfs_t *lfs, const struct lfs_config *config);
int _ts_lfs_mount(lfs_t *lfs, const struct lfs_config *config);
int _ts_lfs_unmount(lfs_t *lfs);
int _ts_lfs_remove(lfs_t *lfs, const char *path);
int _ts_lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
int _ts_lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
lfs_ssize_t _ts_lfs_getattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size);
int _ts_lfs_setattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size);
int _ts_lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
int _ts_lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags);
int _ts_lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, const char *path, int flags, const struct lfs_file_config *config);
int _ts_lfs_file_close(lfs_t *lfs, lfs_file_t *file);
int _ts_lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
lfs_ssize_t _ts_lfs_file_read(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size);
lfs_ssize_t _ts_lfs_file_write(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size);
lfs_soff_t _ts_lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence);
int _ts_lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
lfs_soff_t _ts_lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
int _ts_lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
lfs_soff_t _ts_lfs_file_size(lfs_t *lfs, lfs_file_t *file);
int _ts_lfs_mkdir(lfs_t *lfs, const char *path);
int _ts_lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
int _ts_lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
int _ts_lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
int _ts_lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
lfs_soff_t _ts_lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
int _ts_lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
lfs_ssize_t _ts_lfs_fs_size(lfs_t *lfs);
int _ts_lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data);
int _ts_lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg);
#define lfs_format _ts_lfs_format
#define lfs_mount _ts_lfs_mount
#define lfs_unmount _ts_lfs_unmount
#define lfs_remove _ts_lfs_remove
#define lfs_rename _ts_lfs_rename
#define lfs_stat _ts_lfs_stat
#define lfs_getattr _ts_lfs_getattr
#define lfs_setattr _ts_lfs_setattr
#define lfs_removeattr _ts_lfs_removeattr
#define lfs_file_open _ts_lfs_file_open
#define lfs_file_opencfg _ts_lfs_file_opencfg
#define lfs_file_close _ts_lfs_file_close
#define lfs_file_sync _ts_lfs_file_sync
#define lfs_file_read _ts_lfs_file_read
#define lfs_file_write _ts_lfs_file_write
#define lfs_file_seek _ts_lfs_file_seek
#define lfs_file_truncate _ts_lfs_file_truncate
#define lfs_file_tell _ts_lfs_file_tell
#define lfs_file_rewind _ts_lfs_file_rewind
#define lfs_file_size _ts_lfs_file_size
#define lfs_mkdir _ts_lfs_mkdir
#define lfs_dir_open _ts_lfs_dir_open
#define lfs_dir_close _ts_lfs_dir_close
#define lfs_dir_read _ts_lfs_dir_read
#define lfs_dir_seek _ts_lfs_dir_seek
#define lfs_dir_tell _ts_lfs_dir_tell
#define lfs_dir_rewind _ts_lfs_dir_rewind
#define lfs_fs_size _ts_lfs_fs_size
#define lfs_fs_traverse _ts_lfs_fs_traverse
#define lfs_migrate _ts_lfs_migrate
#else
#define lfs_format _lfs_format
#define lfs_mount _lfs_mount
#define lfs_unmount _lfs_unmount
#define lfs_remove _lfs_remove
#define lfs_rename _lfs_rename
#define lfs_stat _lfs_stat
#define lfs_getattr _lfs_getattr
#define lfs_setattr _lfs_setattr
#define lfs_removeattr _lfs_removeattr
#define lfs_file_open _lfs_file_open
#define lfs_file_opencfg _lfs_file_opencfg
#define lfs_file_close _lfs_file_close
#define lfs_file_sync _lfs_file_sync
#define lfs_file_read _lfs_file_read
#define lfs_file_write _lfs_file_write
#define lfs_file_seek _lfs_file_seek
#define lfs_file_truncate _lfs_file_truncate
#define lfs_file_tell _lfs_file_tell
#define lfs_file_rewind _lfs_file_rewind
#define lfs_file_size _lfs_file_size
#define lfs_mkdir _lfs_mkdir
#define lfs_dir_open _lfs_dir_open
#define lfs_dir_close _lfs_dir_close
#define lfs_dir_read _lfs_dir_read
#define lfs_dir_seek _lfs_dir_seek
#define lfs_dir_tell _lfs_dir_tell
#define lfs_dir_rewind _lfs_dir_rewind
#define lfs_fs_size _lfs_fs_size
#define lfs_fs_traverse _lfs_fs_traverse
#define lfs_migrate _lfs_migrate
#endif

View File

@@ -43,9 +43,6 @@ extern "C"
{
#endif
#ifndef LFS_THREAD_SAFE
#define LFS_THREAD_SAFE 0
#endif
// Macros, may be replaced by system specific wrappers. Arguments to these
// macros must not have side-effects as the macros can be removed for a smaller

View File

@@ -106,7 +106,7 @@ def main(args):
struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff'))))
print("%-47s%s" % ("littlefs v%s.%s" % version,
"data (truncated, if it fits)"
if not any([args.no_truncate, args.tags, args.log, args.all]) else ""))
if not any([args.no_truncate, args.log, args.all]) else ""))
# print gstate
print("gstate 0x%s" % ''.join('%02x' % c for c in gstate))

View File

@@ -746,9 +746,9 @@ if __name__ == "__main__":
parser.add_argument('testpaths', nargs='*', default=[TESTDIR],
help="Description of test(s) to run. By default, this is all tests \
found in the \"{0}\" directory. Here, you can specify a different \
directory of tests, a specific file, a suite by name, and even a \
specific test case by adding brackets. For example \
\"test_dirs[0]\" or \"{0}/test_dirs.toml[0]\".".format(TESTDIR))
directory of tests, a specific file, a suite by name, and even \
specific test cases and permutations. For example \
\"test_dirs#1\" or \"{0}/test_dirs.toml#1#1\".".format(TESTDIR))
parser.add_argument('-D', action='append', default=[],
help="Overriding parameter definitions.")
parser.add_argument('-v', '--verbose', action='store_true',