diff --git a/README.md b/README.md index 6d9a275..00601d9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ # mkspiffs Tool to build and unpack [SPIFFS](https://github.com/pellepl/spiffs) images. +## **IMPORTANT** - building for ESP32 esp-idf spiffs +--- +The **sdkconfig.h** from your application using spiffs has to be used in build process! +Before building **mkspiffs**, copy the **sdkconfig.h** from your application **build/include** directory to **mkspiffs/include** +After every change to spiffs configuration **rebuild mkspiffs** + ## Usage diff --git a/include/sdkconfig.h b/include/sdkconfig.h new file mode 100644 index 0000000..be2b664 --- /dev/null +++ b/include/sdkconfig.h @@ -0,0 +1,5 @@ +/* + * + * Dummy sdkconfig.h file. + * + */ diff --git a/include/sdkconfig_esp32.h b/include/sdkconfig_esp32.h new file mode 100644 index 0000000..a06fe30 --- /dev/null +++ b/include/sdkconfig_esp32.h @@ -0,0 +1,17 @@ +/* + * + * Automatically generated file; DO NOT EDIT. + * Espressif IoT Development Framework Configuration + * + */ +#define CONFIG_SPIFFS_USE_MAGIC_LENGTH 1 +#define CONFIG_SPIFFS_CACHE_WR 1 +#define CONFIG_SPIFFS_CACHE 1 +#define CONFIG_SPIFFS_USE_DIR 1 +#define CONFIG_SPIFFS_META_LENGTH 5 +#define CONFIG_SPIFFS_USE_MAGIC 1 +#define CONFIG_SPIFFS_PAGE_CHECK 1 +#define CONFIG_SPIFFS_USE_MTIME 1 +#define CONFIG_SPIFFS_GC_MAX_RUNS 10 +#define CONFIG_SPIFFS_MAX_PARTITIONS 3 +#define CONFIG_SPIFFS_OBJ_NAME_LEN 32 diff --git a/include/spiffs_config.h b/include/spiffs_config.h index 7820909..4eb36de 100755 --- a/include/spiffs_config.h +++ b/include/spiffs_config.h @@ -18,6 +18,7 @@ #include #include #include +#include // Set generic spiffs debug output call. #ifndef SPIFFS_DBG @@ -77,33 +78,54 @@ typedef uint8_t u8_t; // Enables/disable memory read caching of nucleus file system operations. // If enabled, memory area must be provided for cache in SPIFFS_mount. -#ifndef SPIFFS_CACHE -#define SPIFFS_CACHE 1 +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE (1) #endif + #if SPIFFS_CACHE // Enables memory write caching for file descriptors in hydrogen -#ifndef SPIFFS_CACHE_WR -#define SPIFFS_CACHE_WR 1 +#ifndef SPIFFS_CACHE_WR +#ifndef CONFIG_SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR (0) +#else +#define SPIFFS_CACHE_WR (1) +#endif #endif // Enable/disable statistics on caching. Debug/test purpose only. -#ifndef SPIFFS_CACHE_STATS -#define SPIFFS_CACHE_STATS 0 +#ifndef SPIFFS_CACHE_STATS +#ifdef CONFIG_SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS (1) +#else +#define SPIFFS_CACHE_STATS (0) +#endif #endif #endif // Always check header of each accessed page to ensure consistent state. // If enabled it will increase number of reads, will increase flash. #ifndef SPIFFS_PAGE_CHECK -#define SPIFFS_PAGE_CHECK 1 +#ifndef CONFIG_SPIFFS_PAGE_CHECK +#define SPIFFS_PAGE_CHECK (0) +#else +#define SPIFFS_PAGE_CHECK (1) +#endif #endif // Define maximum number of gc runs to perform to reach desired free pages. +#ifdef CONFIG_SPIFFS_GC_MAX_RUNS +#define SPIFFS_GC_MAX_RUNS CONFIG_SPIFFS_GC_MAX_RUNS +#else #define SPIFFS_GC_MAX_RUNS 10 +#endif // Enable/disable statistics on gc. Debug/test purpose only. #ifndef SPIFFS_GC_STATS -#define SPIFFS_GC_STATS 0 +#ifdef CONFIG_SPIFFS_GC_STATS +#define SPIFFS_GC_STATS (1) +#else +#define SPIFFS_GC_STATS (0) +#endif #endif // Garbage collecting examines all pages in a block which and sums up @@ -125,8 +147,11 @@ typedef uint8_t u8_t; // Object name maximum length. Note that this length include the // zero-termination character, meaning maximum string of characters // can at most be SPIFFS_OBJ_NAME_LEN - 1. +#ifdef CONFIG_SPIFFS_OBJ_NAME_LEN +#define SPIFFS_OBJ_NAME_LEN (CONFIG_SPIFFS_OBJ_NAME_LEN) +#else #define SPIFFS_OBJ_NAME_LEN (32) - +#endif // Maximum length of the metadata associated with an object. // Setting to non-zero value enables metadata-related API but also // changes the on-disk format, so the change is not backward-compatible. @@ -137,7 +162,11 @@ typedef uint8_t u8_t; // This is derived from following: // logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) + // spiffs_object_ix_header fields + at least some LUT entries) +#ifdef CONFIG_SPIFFS_META_LENGTH +#define SPIFFS_OBJ_META_LEN (CONFIG_SPIFFS_META_LENGTH) +#else #define SPIFFS_OBJ_META_LEN (0) +#endif // Size of buffer allocated on stack used when copying data. // Lower value generates more read/writes. No meaning having it bigger @@ -151,8 +180,12 @@ typedef uint8_t u8_t; // not on mount point. If not, SPIFFS_format must be called prior to mounting // again. #ifndef SPIFFS_USE_MAGIC +#ifndef CONFIG_SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#else #define SPIFFS_USE_MAGIC (1) #endif +#endif #if SPIFFS_USE_MAGIC // Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is @@ -161,9 +194,13 @@ typedef uint8_t u8_t; // be accepted for mounting with a configuration defining the filesystem as 2 // megabytes. #ifndef SPIFFS_USE_MAGIC_LENGTH +#ifndef CONFIG_SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH (0) +#else #define SPIFFS_USE_MAGIC_LENGTH (1) #endif #endif +#endif // SPIFFS_USE_MAGIC // SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level // These should be defined on a multithreaded system @@ -185,7 +222,7 @@ typedef uint8_t u8_t; // Enable this if you want the HAL callbacks to be called with the spiffs struct #ifndef SPIFFS_HAL_CALLBACK_EXTRA -#define SPIFFS_HAL_CALLBACK_EXTRA 0 +#define SPIFFS_HAL_CALLBACK_EXTRA 1 #endif // Enable this if you want to add an integer offset to all file handles @@ -194,9 +231,7 @@ typedef uint8_t u8_t; // belongs. // NB: This adds config field fh_ix_offset in the configuration struct when // mounting, which must be defined. -#ifndef SPIFFS_FILEHDL_OFFSET #define SPIFFS_FILEHDL_OFFSET 0 -#endif // Enable this to compile a read only version of spiffs. // This will reduce binary size of spiffs. All code comprising modification @@ -261,10 +296,15 @@ typedef uint8_t u8_t; // Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function // in the api. This function will visualize all filesystem using given printf -// function.. +// function. #ifndef SPIFFS_TEST_VISUALISATION -#define SPIFFS_TEST_VISUALISATION 1 +#ifndef CONFIG_SPIFFS_TEST_VISUALISATION +#define SPIFFS_TEST_VISUALISATION 0 +#else +#define SPIFFS_TEST_VISUALISATION 1 +#endif #endif + #if SPIFFS_TEST_VISUALISATION #ifndef spiffs_printf #define spiffs_printf(...) printf(__VA_ARGS__) diff --git a/main.cpp b/main.cpp index e6482db..507a80e 100644 --- a/main.cpp +++ b/main.cpp @@ -9,6 +9,8 @@ #include #include "spiffs.h" +#include "spiffs_nucleus.h" +#include #include #include #include @@ -21,6 +23,21 @@ #include "tclap/CmdLine.h" #include "tclap/UnlabeledValueArg.h" +#if defined (CONFIG_SPIFFS_USE_MTIME) || defined (CONFIG_SPIFFS_USE_DIR) +/** + * @brief SPIFFS metadata structure + */ +typedef struct { +#ifdef CONFIG_SPIFFS_USE_MTIME + s32_t mtime; /*!< file modification time */ +#endif +#ifdef CONFIG_SPIFFS_USE_DIR + u8_t type; /*!< file type */ +#endif +} __attribute__((packed, aligned(1))) spiffs_meta_t; +#endif + + static std::vector s_flashmem; static std::string s_dirName; @@ -49,6 +66,22 @@ static const char* ignored_file_names[] = { ".gitmodules" }; +#if SPIFFS_HAL_CALLBACK_EXTRA +static s32_t api_spiffs_read(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst){ + memcpy(dst, &s_flashmem[0] + addr, size); + return SPIFFS_OK; +} + +static s32_t api_spiffs_write(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src){ + memcpy(&s_flashmem[0] + addr, src, size); + return SPIFFS_OK; +} + +static s32_t api_spiffs_erase(struct spiffs_t *fs, u32_t addr, u32_t size){ + memset(&s_flashmem[0] + addr, 0xff, size); + return SPIFFS_OK; +} +#else static s32_t api_spiffs_read(u32_t addr, u32_t size, u8_t *dst){ memcpy(dst, &s_flashmem[0] + addr, size); return SPIFFS_OK; @@ -63,7 +96,7 @@ static s32_t api_spiffs_erase(u32_t addr, u32_t size){ memset(&s_flashmem[0] + addr, 0xff, size); return SPIFFS_OK; } - +#endif @@ -85,8 +118,8 @@ int spiffsTryMount(){ const int maxOpenFiles = 4; s_spiffsWorkBuf.resize(s_pageSize * 2); - s_spiffsFds.resize(32 * maxOpenFiles); - s_spiffsCache.resize((32 + s_pageSize) * maxOpenFiles); + s_spiffsFds.resize(sizeof(spiffs_fd) * maxOpenFiles); + s_spiffsCache.resize(sizeof(spiffs_cache) + maxOpenFiles * (sizeof(spiffs_cache_page) + cfg.log_page_size)); return SPIFFS_mount(&s_fs, &cfg, &s_spiffsWorkBuf[0], @@ -116,6 +149,62 @@ void spiffsUnmount(){ SPIFFS_unmount(&s_fs); } +static void spiffs_update_meta(spiffs *fs, spiffs_file fd, u8_t type) +{ +#if defined (CONFIG_SPIFFS_USE_MTIME) || defined (CONFIG_SPIFFS_USE_DIR) + spiffs_meta_t meta; +#ifdef CONFIG_SPIFFS_USE_MTIME + meta.mtime = time(NULL); +#endif //CONFIG_SPIFFS_USE_MTIME + +#ifdef CONFIG_SPIFFS_USE_DIR + // Add file type (directory or regular file) to the last byte of metadata + meta.type = type; +#endif + int ret = SPIFFS_fupdate_meta(fs, fd, (uint8_t *)&meta); + if (ret != SPIFFS_OK) { + std::cerr << "error: Failed to update metadata: " << ret << std::endl; + } +#endif +} + +/* +static time_t spiffs_get_mtime(const spiffs_stat* s) +{ + time_t t = 0; +#ifdef CONFIG_SPIFFS_USE_MTIME + spiffs_meta_t meta; + memcpy(&meta, s->meta, sizeof(meta)); + t = meta.mtime; +#endif + return t; +} + + +static int get_spiffs_stat(const char * path, struct stat * st) +{ + spiffs_stat s; + off_t res = SPIFFS_stat(&s_fs, path, &s); + if (res < 0) { + SPIFFS_clearerr(&s_fs); + return -1; + } + + st->st_size = s.size; +#ifdef CONFIG_SPIFFS_USE_DIR + spiffs_meta_t *meta = (spiffs_meta_t *)&s.meta; + if (meta->type == SPIFFS_TYPE_DIR) st->st_mode = S_IFDIR; + else st->st_mode = S_IFREG; +#else + st->st_mode = (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG; +#endif + st->st_mtime = spiffs_get_mtime(&s); + st->st_atime = 0; + st->st_ctime = 0; + return res; +} +*/ + int addFile(char* name, const char* path) { FILE* src = fopen(path, "rb"); if (!src) { @@ -124,6 +213,7 @@ int addFile(char* name, const char* path) { } spiffs_file dst = SPIFFS_open(&s_fs, name, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0); + spiffs_update_meta(&s_fs, dst, SPIFFS_TYPE_FILE); // read file size fseek(src, 0, SEEK_END); @@ -213,6 +303,29 @@ int addFiles(const char* dirname, const char* subPath) { if (!S_ISREG(path_stat.st_mode)) { // Check if path is a directory. if (S_ISDIR(path_stat.st_mode)) { +#ifdef CONFIG_SPIFFS_USE_DIR + std::string dirpath = subPath; + dirpath += ent->d_name; + std::cout << dirpath << " [D]" << std::endl; + spiffs_file dst = SPIFFS_open(&s_fs, (char*)dirpath.c_str(), SPIFFS_CREAT | SPIFFS_WRONLY, 0); + if (dst < 0) { + std::cerr << "error adding directory (open)!" << std::endl; + error = true; + if (s_debugLevel > 0) { + std::cout << std::endl; + } + break; + } + spiffs_update_meta(&s_fs, dst, SPIFFS_TYPE_DIR); + if (SPIFFS_close(&s_fs, dst) < 0) { + std::cerr << "error adding directory (close)!" << std::endl; + error = true; + if (s_debugLevel > 0) { + std::cout << std::endl; + } + break; + } +#endif // Prepare new sub path. std::string newSubPath = subPath; newSubPath += ent->d_name; @@ -259,6 +372,7 @@ int addFiles(const char* dirname, const char* subPath) { void listFiles() { spiffs_DIR dir; spiffs_dirent ent; + //struct stat sb = {0}; SPIFFS_opendir(&s_fs, 0, &dir); spiffs_dirent* it; @@ -267,6 +381,8 @@ void listFiles() { if (!it) break; + //get_spiffs_stat((const char *)it->name, &sb); + //std::cout << sb.st_mode << '\t' << it->size << '\t' << it->name << std::endl; std::cout << it->size << '\t' << it->name << std::endl; } SPIFFS_closedir(&dir); @@ -450,6 +566,7 @@ int actionPack() { spiffsFormat(); int result = addFiles(s_dirName.c_str(), "/"); + //listFiles(); spiffsUnmount(); fwrite(&s_flashmem[0], 4, s_flashmem.size()/4, fdres); @@ -476,7 +593,7 @@ int actionUnpack(void) { } // read content into s_flashmem - fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc); + ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc); // close fiel handle fclose(fdsrc); @@ -505,7 +622,11 @@ int actionList() { return 1; } - fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc); + int ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc); + if (ret < 0) { + std::cerr << "error: failed to read from image file" << std::endl; + return 1; + } fclose(fdsrc); spiffsMount(); listFiles(); @@ -514,6 +635,7 @@ int actionList() { } int actionVisualize() { +#if SPIFFS_TEST_VISUALISATION s_flashmem.resize(s_imageSize, 0xff); FILE* fdsrc = fopen(s_imageName.c_str(), "rb"); @@ -531,7 +653,7 @@ int actionVisualize() { SPIFFS_info(&s_fs, &total, &used); std::cout << "total: " << total << std::endl << "used: " << used << std::endl; spiffsUnmount(); - +#endif return 0; }