Compare commits

...

25 Commits

Author SHA1 Message Date
Christopher Haster
21ef0b7169 WIP added some comments 2018-04-03 09:37:14 -05:00
Christopher Haster
fec133dfba WIP Bumped versions 2018-04-03 08:38:25 -05:00
Christopher Haster
9b4530f8de WIP cleaned up TODOs 2018-04-03 08:29:28 -05:00
Christopher Haster
3a12b40fff WIP added support for inline files up to 1023 bytes 2018-04-03 08:28:09 -05:00
Christopher Haster
12aa4bde06 WIP Added limits on name/attrs/inline sizes 2018-04-01 15:36:29 -05:00
Christopher Haster
09c7df83db WIP Refactored lfs_dir_set function to umbrella append/update/remove 2018-03-27 22:49:21 -05:00
Christopher Haster
5387f52de5 WIP Added lfs_dir_get 2018-03-23 18:36:02 -05:00
Christopher Haster
c5b11d2a62 WIP moved superblock to entry append 2018-03-23 16:11:36 -05:00
Christopher Haster
66cdab8327 WIP fixed bugs 2018-03-23 05:29:18 -05:00
Christopher Haster
8aba03d25f WIP Fixed issue with modifying dir after append in update 2018-03-18 20:37:13 -05:00
Christopher Haster
9064fa6dbb WIP Better implementation of inline files, now with overflowing 2018-03-17 20:32:16 -05:00
Christopher Haster
fcc5c764e4 WIP moved asserts out 2018-03-17 12:10:09 -05:00
Christopher Haster
37f799d8a2 WIP added hacky taped on inline files 2018-03-17 10:29:41 -05:00
Christopher Haster
04b1103de1 WIP Fixed big-endian support 2018-03-15 23:25:21 -05:00
Christopher Haster
87df75d009 WIP added entry size field 2018-03-15 23:25:09 -05:00
Christopher Haster
1ea3d04d9c WIP separated dir_remove for two types of arguments 2018-03-15 23:24:50 -05:00
Christopher Haster
126f6d334e WIP minor improvement to from-memory commits 2018-03-12 22:29:21 -05:00
Christopher Haster
385b74944d WIP Allowed taking advantage of empty space earlier in dir search 2018-03-12 22:29:21 -05:00
Christopher Haster
3a10f5c29b WIP added callbacks for stuff 2018-03-12 22:29:21 -05:00
Christopher Haster
96cca2f5b6 WIP Moved entry tag updates out 2018-03-12 22:29:21 -05:00
Christopher Haster
32f43462ea WIP Naive implementation of resizable entries 2018-03-12 22:29:21 -05:00
Christopher Haster
efc634f3ed WIP something something flexible updates 2018-03-12 22:29:21 -05:00
Christopher Haster
2f7adc3461 WIP adopted lisp-like dsl for more flexibility 2018-03-12 22:29:21 -05:00
Christopher Haster
e934a22c3a WIP Changed commit DSL to support disk->disk copies 2018-03-12 22:29:21 -05:00
Christopher Haster
5937fd79dd Separated type/struct fields in dir entries
The separation of data-structure vs entry type has been implicit for a
while now, and even taken advantage of to simplify the traverse logic.
2018-03-12 22:29:21 -05:00
5 changed files with 732 additions and 378 deletions

950
lfs.c

File diff suppressed because it is too large Load Diff

128
lfs.h
View File

@@ -27,14 +27,14 @@
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_VERSION 0x00010003
#define LFS_VERSION 0x00010004
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
// Version of On-disk data structures
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS_DISK_VERSION 0x00010001
#define LFS_DISK_VERSION 0x00010002
#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16))
#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0))
@@ -50,51 +50,78 @@ typedef int32_t lfs_soff_t;
typedef uint32_t lfs_block_t;
// Max name size in bytes
// Maximum inline file size in bytes. Large inline files require a larger
// read and prog cache, but if a file can be inline it does not need its own
// data block. LFS_ATTRS_MAX + LFS_INLINE_MAX must be <= 0xffff. Stored in
// superblock and must be respected by other littlefs drivers.
#ifndef LFS_INLINE_MAX
#define LFS_INLINE_MAX 0x3ff
#endif
// Maximum size of all attributes per file in bytes, may be redefined but a
// a smaller LFS_ATTRS_MAX has no benefit. LFS_ATTRS_MAX + LFS_INLINE_MAX
// must be <= 0xffff. Stored in superblock and must be respected by other
// littlefs drivers.
#ifndef LFS_ATTRS_MAX
#define LFS_ATTRS_MAX 0x3f
#endif
// Max name size in bytes, may be redefined to reduce the size of the
// info struct. Stored in superblock and must be respected by other
// littlefs drivers.
#ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 255
#define LFS_NAME_MAX 0xff
#endif
// Possible error codes, these are negative to allow
// valid positive return values
enum lfs_error {
LFS_ERR_OK = 0, // No error
LFS_ERR_IO = -5, // Error during device operation
LFS_ERR_CORRUPT = -52, // Corrupted
LFS_ERR_NOENT = -2, // No directory entry
LFS_ERR_EXIST = -17, // Entry already exists
LFS_ERR_NOTDIR = -20, // Entry is not a dir
LFS_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number
LFS_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_OK = 0, // No error
LFS_ERR_IO = -5, // Error during device operation
LFS_ERR_CORRUPT = -52, // Corrupted
LFS_ERR_NOENT = -2, // No directory entry
LFS_ERR_EXIST = -17, // Entry already exists
LFS_ERR_NOTDIR = -20, // Entry is not a dir
LFS_ERR_ISDIR = -21, // Entry is a dir
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
LFS_ERR_BADF = -9, // Bad file number
LFS_ERR_INVAL = -22, // Invalid parameter
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NAMETOOLONG = -36, // File name too long
};
// File types
enum lfs_type {
LFS_TYPE_REG = 0x11,
LFS_TYPE_DIR = 0x22,
LFS_TYPE_SUPERBLOCK = 0x2e,
// file type
LFS_TYPE_REG = 0x01,
LFS_TYPE_DIR = 0x02,
LFS_TYPE_SUPERBLOCK = 0x0e,
// on disk structure
LFS_STRUCT_CTZ = 0x10,
LFS_STRUCT_DIR = 0x20,
LFS_STRUCT_INLINE = 0x30,
LFS_STRUCT_MOVED = 0x80,
};
// File open flags
enum lfs_open_flags {
// open flags
LFS_O_RDONLY = 1, // Open a file as read only
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
LFS_O_RDONLY = 1, // Open a file as read only
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
// internally used flags
LFS_F_DIRTY = 0x10000, // File does not match storage
LFS_F_WRITING = 0x20000, // File has been written since last flush
LFS_F_READING = 0x40000, // File has been read since last flush
LFS_F_ERRED = 0x80000, // An error occured during write
LFS_F_DIRTY = 0x010000, // File does not match storage
LFS_F_WRITING = 0x020000, // File has been written since last flush
LFS_F_READING = 0x040000, // File has been read since last flush
LFS_F_ERRED = 0x080000, // An error occured during write
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
};
// File seek flags
@@ -171,6 +198,25 @@ struct lfs_config {
// Optional, statically allocated buffer for files. Must be program sized.
// If enabled, only one file may be opened at a time.
void *file_buffer;
// Optional upper limit on inlined files in bytes. Large inline files
// require a larger read and prog cache, but if a file can be inlined it
// does not need its own data block. Must be smaller than the read size
// and prog size. Defaults to min(LFS_INLINE_MAX, read_size) when zero.
// Stored in superblock and must be respected by other littlefs drivers.
lfs_size_t inline_size;
// Optional upper limit on attributes per file in bytes. No downside for
// larger attributes size but must be less than LFS_ATTRS_MAX. Defaults to
// LFS_ATTRS_MAX when zero.Stored in superblock and must be respected by
// other littlefs drivers.
lfs_size_t attrs_size;
// Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
// superblock and must be respected by other littlefs drivers.
lfs_size_t name_size;
};
@@ -190,6 +236,7 @@ struct lfs_info {
/// littlefs data structures ///
typedef struct lfs_entry {
lfs_off_t off;
lfs_size_t size;
struct lfs_disk_entry {
uint8_t type;
@@ -221,6 +268,7 @@ typedef struct lfs_file {
lfs_size_t size;
uint32_t flags;
lfs_size_t inline_size;
lfs_off_t pos;
lfs_block_t block;
lfs_off_t off;
@@ -243,18 +291,16 @@ typedef struct lfs_dir {
} lfs_dir_t;
typedef struct lfs_superblock {
lfs_off_t off;
struct lfs_disk_superblock {
uint8_t type;
uint8_t elen;
uint8_t alen;
uint8_t nlen;
lfs_block_t root[2];
uint32_t block_size;
uint32_t block_count;
lfs_size_t block_size;
lfs_size_t block_count;
uint32_t version;
char magic[8];
lfs_size_t inline_size;
lfs_size_t attrs_size;
lfs_size_t name_size;
} d;
} lfs_superblock_t;
@@ -279,6 +325,10 @@ typedef struct lfs {
lfs_free_t free;
bool deorphaned;
lfs_size_t inline_size;
lfs_size_t attrs_size;
lfs_size_t name_size;
} lfs_t;

View File

@@ -274,9 +274,12 @@ TEST
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
// create one block whole for half a directory
// create one block hole for half a directory
lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], (void*)"hi", 2) => 2;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => cfg.block_size;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
@@ -289,13 +292,16 @@ tests/test.py << TEST
}
lfs_file_close(&lfs, &file[0]) => 0;
// open whole
// open hole
lfs_remove(&lfs, "bump") => 0;
lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file[0], "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], buffer, size) => LFS_ERR_NOSPC;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0;

View File

@@ -73,7 +73,7 @@ lfs_mktree
lfs_chktree
echo "--- Block corruption ---"
for i in {0..33}
for i in {2..33}
do
rm -rf blocks
mkdir blocks
@@ -83,12 +83,12 @@ do
done
echo "--- Block persistance ---"
for i in {0..33}
for i in {2..33}
do
rm -rf blocks
mkdir blocks
lfs_mktree
chmod a-w blocks/$(printf '%x' $i)
chmod a-w blocks/$(printf '%x' $i) || true
lfs_mktree
lfs_chktree
done

View File

@@ -30,20 +30,10 @@ echo "--- Invalid mount ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
TEST
rm blocks/0 blocks/1
rm -f blocks/0 blocks/1
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
TEST
echo "--- Valid corrupt mount ---"
tests/test.py << TEST
lfs_format(&lfs, &cfg) => 0;
TEST
rm blocks/0
tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0;
lfs_unmount(&lfs) => 0;
TEST
echo "--- Results ---"
tests/stats.py