diff --git a/lfs.c b/lfs.c index 550736287cd..ec21841d302 100644 --- a/lfs.c +++ b/lfs.c @@ -8,7 +8,6 @@ #include "lfs_util.h" #include -#include #include @@ -1086,6 +1085,43 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return lfs_dir_commit(lfs, &cwd, &file->entry, NULL); } +lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size) { + uint8_t *data = buffer; + size = lfs_min(size, file->entry.d.u.file.size - file->rpos); + lfs_size_t nsize = size; + + if ((file->flags & 3) == LFS_O_WRONLY) { + return LFS_ERROR_INVALID; + } + + while (nsize > 0) { + // check if we need a new block + if (!file->rblock || file->roff == lfs->cfg->block_size) { + int err = lfs_index_find(lfs, + file->entry.d.u.file.head, file->entry.d.u.file.size, + file->rpos, &file->rblock, &file->roff); + if (err) { + return err; + } + } + + // read as much as we can in current block + lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->roff); + int err = lfs_bd_read(lfs, file->rblock, file->roff, diff, data); + if (err) { + return err; + } + + file->rpos += diff; + file->roff += diff; + data += diff; + nsize -= diff; + } + + return size; +} + lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size) { const uint8_t *data = buffer; @@ -1144,43 +1180,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, return size; } -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, - void *buffer, lfs_size_t size) { - uint8_t *data = buffer; - size = lfs_min(size, file->entry.d.u.file.size - file->rpos); - lfs_size_t nsize = size; - - if ((file->flags & 3) == LFS_O_WRONLY) { - return LFS_ERROR_INVALID; - } - - while (nsize > 0) { - // check if we need a new block - if (!file->rblock || file->roff == lfs->cfg->block_size) { - int err = lfs_index_find(lfs, - file->entry.d.u.file.head, file->entry.d.u.file.size, - file->rpos, &file->rblock, &file->roff); - if (err) { - return err; - } - } - - // read as much as we can in current block - lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->roff); - int err = lfs_bd_read(lfs, file->rblock, file->roff, diff, data); - if (err) { - return err; - } - - file->rpos += diff; - file->roff += diff; - data += diff; - nsize -= diff; - } - - return size; -} - lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence) { // write out everything beforehand, may be noop if rdonly @@ -1215,10 +1214,6 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, return prev; } -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { - return lfs_max(file->wpos, file->entry.d.u.file.size); -} - lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { return file->rpos; } @@ -1232,8 +1227,180 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { return 0; } +lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { + return lfs_max(file->wpos, file->entry.d.u.file.size); +} + + +/// General fs oprations /// +int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { + lfs_dir_t cwd; + int err = lfs_dir_fetch(lfs, &cwd, lfs->root); + if (err) { + return err; + } + + lfs_entry_t entry; + err = lfs_dir_find(lfs, &cwd, &entry, &path); + if (err) { + return err; + } + + // TODO abstract out info assignment + memset(info, 0, sizeof(*info)); + info->type = entry.d.type & 0xff; + if (info->type == LFS_TYPE_REG) { + info->size = entry.d.u.file.size; + } + + err = lfs_bd_read(lfs, cwd.pair[0], entry.off + sizeof(entry.d), + entry.d.len - sizeof(entry.d), info->name); + if (err) { + return err; + } + + return 0; +} + +int lfs_remove(lfs_t *lfs, const char *path) { + lfs_dir_t cwd; + int err = lfs_dir_fetch(lfs, &cwd, lfs->root); + if (err) { + return err; + } + + lfs_entry_t entry; + err = lfs_dir_find(lfs, &cwd, &entry, &path); + if (err) { + return err; + } + + lfs_dir_t dir; + if (entry.d.type == LFS_TYPE_DIR) { + // must be empty before removal, checking size + // without masking top bit checks for any case where + // dir is not empty + int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir); + if (err) { + return err; + } else if (dir.d.size != sizeof(dir.d)) { + return LFS_ERROR_INVALID; + } + } + + // remove the entry + err = lfs_dir_remove(lfs, &cwd, &entry); + if (err) { + return err; + } + + // if we were a directory, just run a deorphan step, this should + // collect us, although is expensive + if (entry.d.type == LFS_TYPE_DIR) { + int err = lfs_deorphan(lfs); + if (err) { + return err; + } + } + + return 0; +} + +int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { + // find old entry + lfs_dir_t oldcwd; + int err = lfs_dir_fetch(lfs, &oldcwd, lfs->root); + if (err) { + return err; + } + + lfs_entry_t oldentry; + err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath); + if (err) { + return err; + } + + // allocate new entry + lfs_dir_t newcwd; + err = lfs_dir_fetch(lfs, &newcwd, lfs->root); + if (err) { + return err; + } + + lfs_entry_t preventry; + err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath); + if (err && err != LFS_ERROR_NO_ENTRY) { + return err; + } + bool prevexists = (err != LFS_ERROR_NO_ENTRY); + + // must have same type + if (prevexists && preventry.d.type != oldentry.d.type) { + return LFS_ERROR_INVALID; + } + + lfs_dir_t dir; + if (prevexists && preventry.d.type == LFS_TYPE_DIR) { + // must be empty before removal, checking size + // without masking top bit checks for any case where + // dir is not empty + int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir); + if (err) { + return err; + } else if (dir.d.size != sizeof(dir.d)) { + return LFS_ERROR_INVALID; + } + } + + // move to new location + lfs_entry_t newentry = preventry; + newentry.d = oldentry.d; + newentry.d.len = sizeof(newentry.d) + strlen(newpath); + + if (prevexists) { + int err = lfs_dir_commit(lfs, &newcwd, &newentry, newpath); + if (err) { + return err; + } + } else { + int err = lfs_dir_append(lfs, &newcwd, &newentry, newpath); + if (err) { + return err; + } + } + + // fetch again in case newcwd == oldcwd + // TODO handle this better? + err = lfs_dir_fetch(lfs, &oldcwd, oldcwd.pair); + if (err) { + return err; + } + + err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath); + if (err) { + return err; + } + + // remove from old location + err = lfs_dir_remove(lfs, &oldcwd, &oldentry); + if (err) { + return err; + } + + // if we were a directory, just run a deorphan step, this should + // collect us, although is expensive + if (prevexists && preventry.d.type == LFS_TYPE_DIR) { + int err = lfs_deorphan(lfs); + if (err) { + return err; + } + } + + return 0; +} + -/// Generic filesystem operations /// +/// Filesystem operations /// static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs->cfg = cfg; lfs->words = lfs->cfg->block_size / sizeof(uint32_t); @@ -1372,6 +1539,9 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { if (!err) { err = lfs_bd_read(lfs, dir.pair[0], sizeof(dir.d), sizeof(superblock.d), &superblock.d); + + lfs->root[0] = superblock.d.root[0]; + lfs->root[1] = superblock.d.root[1]; } if (err == LFS_ERROR_CORRUPT || @@ -1384,11 +1554,9 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { LFS_ERROR("Invalid version %d.%d\n", 0xffff & (superblock.d.version >> 16), 0xffff & (superblock.d.version >> 0)); + return LFS_ERROR_INVALID; } - lfs->root[0] = superblock.d.root[0]; - lfs->root[1] = superblock.d.root[1]; - return err; } @@ -1396,6 +1564,8 @@ int lfs_unmount(lfs_t *lfs) { return lfs_deinit(lfs); } + +/// Littlefs specific operations /// int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { // iterate over metadata pairs lfs_dir_t dir; @@ -1510,7 +1680,7 @@ int lfs_deorphan(lfs_t *lfs) { if (!parent) { // we are an orphan - LFS_INFO("Orphan %d %d", pdir.d.tail[0], pdir.d.tail[1]); + LFS_DEBUG("Orphan %d %d", pdir.d.tail[0], pdir.d.tail[1]); pdir.d.tail[0] = cdir.d.tail[0]; pdir.d.tail[1] = cdir.d.tail[1]; @@ -1529,168 +1699,3 @@ int lfs_deorphan(lfs_t *lfs) { return 0; } -int lfs_remove(lfs_t *lfs, const char *path) { - lfs_dir_t cwd; - int err = lfs_dir_fetch(lfs, &cwd, lfs->root); - if (err) { - return err; - } - - lfs_entry_t entry; - err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err) { - return err; - } - - lfs_dir_t dir; - if (entry.d.type == LFS_TYPE_DIR) { - // must be empty before removal, checking size - // without masking top bit checks for any case where - // dir is not empty - int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir); - if (err) { - return err; - } else if (dir.d.size != sizeof(dir.d)) { - return LFS_ERROR_INVALID; - } - } - - // remove the entry - err = lfs_dir_remove(lfs, &cwd, &entry); - if (err) { - return err; - } - - // if we were a directory, just run a deorphan step, this should - // collect us, although is expensive - if (entry.d.type == LFS_TYPE_DIR) { - int err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - - return 0; -} - -int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { - // find old entry - lfs_dir_t oldcwd; - int err = lfs_dir_fetch(lfs, &oldcwd, lfs->root); - if (err) { - return err; - } - - lfs_entry_t oldentry; - err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath); - if (err) { - return err; - } - - // allocate new entry - lfs_dir_t newcwd; - err = lfs_dir_fetch(lfs, &newcwd, lfs->root); - if (err) { - return err; - } - - lfs_entry_t preventry; - err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath); - if (err && err != LFS_ERROR_NO_ENTRY) { - return err; - } - bool prevexists = (err != LFS_ERROR_NO_ENTRY); - - // must have same type - if (prevexists && preventry.d.type != oldentry.d.type) { - return LFS_ERROR_INVALID; - } - - lfs_dir_t dir; - if (prevexists && preventry.d.type == LFS_TYPE_DIR) { - // must be empty before removal, checking size - // without masking top bit checks for any case where - // dir is not empty - int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir); - if (err) { - return err; - } else if (dir.d.size != sizeof(dir.d)) { - return LFS_ERROR_INVALID; - } - } - - // move to new location - lfs_entry_t newentry = preventry; - newentry.d = oldentry.d; - newentry.d.len = sizeof(newentry.d) + strlen(newpath); - - if (prevexists) { - int err = lfs_dir_commit(lfs, &newcwd, &newentry, newpath); - if (err) { - return err; - } - } else { - int err = lfs_dir_append(lfs, &newcwd, &newentry, newpath); - if (err) { - return err; - } - } - - // fetch again in case newcwd == oldcwd - // TODO handle this better? - err = lfs_dir_fetch(lfs, &oldcwd, oldcwd.pair); - if (err) { - return err; - } - - err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath); - if (err) { - return err; - } - - // remove from old location - err = lfs_dir_remove(lfs, &oldcwd, &oldentry); - if (err) { - return err; - } - - // if we were a directory, just run a deorphan step, this should - // collect us, although is expensive - if (prevexists && preventry.d.type == LFS_TYPE_DIR) { - int err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - - return 0; -} - -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { - lfs_dir_t cwd; - int err = lfs_dir_fetch(lfs, &cwd, lfs->root); - if (err) { - return err; - } - - lfs_entry_t entry; - err = lfs_dir_find(lfs, &cwd, &entry, &path); - if (err) { - return err; - } - - // TODO abstract out info assignment - memset(info, 0, sizeof(*info)); - info->type = entry.d.type & 0xff; - if (info->type == LFS_TYPE_REG) { - info->size = entry.d.u.file.size; - } - - err = lfs_bd_read(lfs, cwd.pair[0], entry.off + sizeof(entry.d), - entry.d.len - sizeof(entry.d), info->name); - if (err) { - return err; - } - - return 0; -} diff --git a/lfs.h b/lfs.h index f091a66a177..39b461d0615 100644 --- a/lfs.h +++ b/lfs.h @@ -7,9 +7,25 @@ #ifndef LFS_H #define LFS_H -#include "lfs_config.h" +#include +#include +// Type definitions +typedef uint32_t lfs_size_t; +typedef uint32_t lfs_off_t; + +typedef int32_t lfs_ssize_t; +typedef int32_t lfs_soff_t; + +typedef uint32_t lfs_block_t; + + +// Configurable littlefs constants +#ifndef LFS_NAME_MAX +#define LFS_NAME_MAX 255 +#endif + // The littefs constants enum lfs_error { LFS_ERROR_OK = 0, @@ -109,7 +125,7 @@ struct lfs_info { }; -// Internal data structures +// littlefs data structures typedef struct lfs_entry { lfs_block_t pair[2]; lfs_off_t off; @@ -169,8 +185,7 @@ typedef struct lfs_superblock { } d; } lfs_superblock_t; - -// Little filesystem type +// littlefs type typedef struct lfs { const struct lfs_config *cfg; lfs_size_t words; // number of 32-bit words that can fit in a block @@ -191,15 +206,17 @@ typedef struct lfs { } lfs_t; -// Functions +// filesystem functions int lfs_format(lfs_t *lfs, const struct lfs_config *config); int lfs_mount(lfs_t *lfs, const struct lfs_config *config); int lfs_unmount(lfs_t *lfs); +// general operations int lfs_remove(lfs_t *lfs, const char *path); int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); +// directory operations int lfs_mkdir(lfs_t *lfs, const char *path); int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); @@ -208,20 +225,22 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); +// file operations int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags); int lfs_file_close(lfs_t *lfs, lfs_file_t *file); int lfs_file_sync(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); lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size); +lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size); lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence); -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); +lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); +// miscellaneous lfs specific operations int lfs_deorphan(lfs_t *lfs); int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); diff --git a/lfs_config.h b/lfs_config.h deleted file mode 100644 index 6368488bd5f..00000000000 --- a/lfs_config.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Configuration and type definitions - * - * Copyright (c) 2017 Christopher Haster - * Distributed under the MIT license - */ -#ifndef LFS_CONFIG_H -#define LFS_CONFIG_H - -#include - -// Type definitions -typedef uint32_t lfs_size_t; -typedef uint32_t lfs_off_t; - -typedef int32_t lfs_ssize_t; -typedef int32_t lfs_soff_t; - -typedef uint32_t lfs_block_t; - -// Maximum length of file name -#ifndef LFS_NAME_MAX -#define LFS_NAME_MAX 255 -#endif - -// Logging operations -#include -#define LFS_ERROR(fmt, ...) printf("lfs error: " fmt "\n", __VA_ARGS__) -#define LFS_WARN(fmt, ...) printf("lfs warn: " fmt "\n", __VA_ARGS__) -#define LFS_INFO(fmt, ...) printf("lfs info: " fmt "\n", __VA_ARGS__) - - -#endif diff --git a/lfs_util.c b/lfs_util.c index edac0a5ac3c..69faa2b2741 100644 --- a/lfs_util.c +++ b/lfs_util.c @@ -7,7 +7,7 @@ #include "lfs_util.h" -uint32_t lfs_crc(uint32_t crc, lfs_size_t size, const void *buffer) { +uint32_t lfs_crc(uint32_t crc, size_t size, const void *buffer) { static const uint32_t rtable[16] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, @@ -17,7 +17,7 @@ uint32_t lfs_crc(uint32_t crc, lfs_size_t size, const void *buffer) { const uint8_t *data = buffer; - for (lfs_size_t i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; } diff --git a/lfs_util.h b/lfs_util.h index c20312c41bd..533ef117739 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -7,8 +7,9 @@ #ifndef LFS_UTIL_H #define LFS_UTIL_H -#include "lfs_config.h" #include +#include +#include // Builtin functions @@ -32,7 +33,13 @@ static inline int lfs_scmp(uint32_t a, uint32_t b) { return (int)(unsigned)(a - b); } -uint32_t lfs_crc(uint32_t crc, lfs_size_t size, const void *buffer); +uint32_t lfs_crc(uint32_t crc, size_t size, const void *buffer); + + +// Logging functions +#define LFS_DEBUG(fmt, ...) printf("lfs debug: " fmt "\n", __VA_ARGS__) +#define LFS_WARN(fmt, ...) printf("lfs warn: " fmt "\n", __VA_ARGS__) +#define LFS_ERROR(fmt, ...) printf("lfs error: " fmt "\n", __VA_ARGS__) #endif