From 58cc0a1847c4eaf08be3ac25b19c37bb5c21aef1 Mon Sep 17 00:00:00 2001 From: Lucjan Bryndza Date: Tue, 15 Dec 2020 12:37:59 +0100 Subject: [PATCH] [EGD-4760] littlefs host tools (#1161) * [EGD-4760] Remove littlefs sumbmodule * [EGD-4760] littlefs submodule in new location * [EGD-4760] Littlefs host tools inital build * [EGD-4760] Find fdisk * [EGD-4760] LFS Cmake file changed * [EGD-4760] GenLittlefs work in progress * [EGD-4760] Parse args in the tool * [EGD-4760] Inital version of genlittlefs * [EGD-4760] genlittle fs seams to be working It is a first working release for genlittle fs Signed-off-by: Lucjan Bryndza * [EGD-4760] genlittle Speed improvement Signed-off-by: Lucjan Bryndza * [EGD-4760] genlittlefs verbose flag Signed-off-by: Lucjan Bryndza * [EGD-4760] genlittlefs fix file support Signed-off-by: Lucjan Bryndza * [EGD-4760] Check if it is a littlefs * [EGD-4760] Genlittle fs image * [EGD-4760] Gen image fixed * [EGD-4760] Final version of genlittlefs * [EGD-4760] Rename littlefs rootdir. * [EGD-4760] Code review round #1 fixes --- .gitmodules | 7 +- CMakeLists.txt | 2 + host-tools/CMakeLists.txt | 18 + host-tools/genlittlefs/CMake/FindBLKID.cmake | 35 ++ host-tools/genlittlefs/CMakeLists.txt | 21 + host-tools/genlittlefs/lfs_ioaccess.c | 246 ++++++++++++ host-tools/genlittlefs/lfs_ioaccess.h | 17 + host-tools/genlittlefs/mklfs.c | 373 ++++++++++++++++++ host-tools/genlittlefs/parse_args.c | 331 ++++++++++++++++ host-tools/genlittlefs/parse_args.h | 36 ++ host-tools/genlittlefs/parse_partitions.c | 63 +++ host-tools/genlittlefs/parse_partitions.h | 24 ++ host-tools/littlefs-fuse/CMake/FindFUSE.cmake | 34 ++ host-tools/littlefs-fuse/CMakeLists.txt | 26 ++ host-tools/littlefs-fuse/lfsfuse | 1 + module-vfs/CMakeLists.txt | 4 +- .../{littlefs.cmake => lfsfs/CMakeLists.txt} | 20 +- module-vfs/thirdparty/lfsfs/littlefs | 1 + module-vfs/thirdparty/littlefs | 1 - 19 files changed, 1250 insertions(+), 10 deletions(-) create mode 100644 host-tools/CMakeLists.txt create mode 100644 host-tools/genlittlefs/CMake/FindBLKID.cmake create mode 100644 host-tools/genlittlefs/CMakeLists.txt create mode 100644 host-tools/genlittlefs/lfs_ioaccess.c create mode 100644 host-tools/genlittlefs/lfs_ioaccess.h create mode 100644 host-tools/genlittlefs/mklfs.c create mode 100644 host-tools/genlittlefs/parse_args.c create mode 100644 host-tools/genlittlefs/parse_args.h create mode 100644 host-tools/genlittlefs/parse_partitions.c create mode 100644 host-tools/genlittlefs/parse_partitions.h create mode 100644 host-tools/littlefs-fuse/CMake/FindFUSE.cmake create mode 100644 host-tools/littlefs-fuse/CMakeLists.txt create mode 160000 host-tools/littlefs-fuse/lfsfuse rename module-vfs/thirdparty/{littlefs.cmake => lfsfs/CMakeLists.txt} (56%) create mode 160000 module-vfs/thirdparty/lfsfs/littlefs delete mode 160000 module-vfs/thirdparty/littlefs diff --git a/.gitmodules b/.gitmodules index c0a50c2ae19137a3867f76dc6310df3ef6bafb36..e93d4606f07c27ed5c111ee0c075ceab0e4f11dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -65,6 +65,9 @@ [submodule "module-vfs/thirdparty/fatfs"] path = module-vfs/thirdparty/fatfs url = ../fatfs.git -[submodule "module-vfs/thirdparty/littlefs"] - path = module-vfs/thirdparty/littlefs +[submodule "host-tools/littlefs-fuse/lfsfuse"] + path = host-tools/littlefs-fuse/lfsfuse + url = https://github.com/littlefs-project/littlefs-fuse.git +[submodule "module-vfs/thirdparty/lfsfs/littlefs"] + path = module-vfs/thirdparty/lfsfs/littlefs url = https://github.com/littlefs-project/littlefs.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 18e2ee97328bc95b97f580f947ad1e59c4bf3295..f4c3b4a8453e8c6643f4c523fd2773b17402662b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ if (${ENABLE_TESTS}) add_subdirectory(test) endif () +add_subdirectory(host-tools) add_custom_target(assets) # setting build flags @@ -220,6 +221,7 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_Linux") install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION "./") endif() + if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051") set(HEX_FILE ${CMAKE_PROJECT_NAME}.hex) set(BIN_FILE boot.bin) diff --git a/host-tools/CMakeLists.txt b/host-tools/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7038c8575822dbe164be3b5a7ca3b9ef3625d5e --- /dev/null +++ b/host-tools/CMakeLists.txt @@ -0,0 +1,18 @@ +if (CMAKE_CROSSCOMPILING) + # Littlefs fuse is needed in rt1051 and Linux for manipulate images + # genlittlefs is needed only on the Linux image for generate emulator target image + add_custom_target( + lfsfuse ALL + COMMAND ${CMAKE_COMMAND} + -DCMAKE_BUILD_TYPE:STRING="Release" + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE:PATH="${CMAKE_BINARY_DIR}" + -B"build" + -H"${CMAKE_SOURCE_DIR}/host-tools/littlefs-fuse" + COMMAND ${CMAKE_COMMAND} --build build --config Release + ) +else() + set(_genlittlefs "${CMAKE_BINARY_DIR}/genlittlefs${CMAKE_EXECUTABLE_SUFFIX}") + add_subdirectory(genlittlefs) + add_subdirectory(littlefs-fuse) +endif() + diff --git a/host-tools/genlittlefs/CMake/FindBLKID.cmake b/host-tools/genlittlefs/CMake/FindBLKID.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b4267b2844d8663236a1329634103fe4e1bb54ee --- /dev/null +++ b/host-tools/genlittlefs/CMake/FindBLKID.cmake @@ -0,0 +1,35 @@ +# Find the BLKID includes and library +# +# BLKID_INCLUDE_DIR - where to find fuse.h, etc. +# BLKID_LIBRARIES - List of libraries when using FDISK. +# BLKID_FOUND - True if FDISK lib is found. + +# check if already in cache, be silent +IF (BLKID_INCLUDE_DIR) + SET (BLKID_FIND_QUIETLY TRUE) +ENDIF (BLKID_INCLUDE_DIR) + +# find includes +FIND_PATH (BLKID_INCLUDE_DIR blkid.h + /usr/local/include/blkid + /usr/local/include + /usr/include + /usr/include/blkid +) + +# find lib +if (APPLE) + SET(BLKID_NAMES libblkid.dylib blkid) +else (APPLE) + SET(BLKID_NAMES blkid) +endif (APPLE) +FIND_LIBRARY(BLKID_LIBRARIES + NAMES ${BLKID_NAMES} + PATHS /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /usr/lib/x86_64-linux-gnu + ) + +include ("FindPackageHandleStandardArgs") +find_package_handle_standard_args ("BLKID" DEFAULT_MSG + BLKID_INCLUDE_DIR BLKID_LIBRARIES) + +mark_as_advanced (BLKID_INCLUDE_DIR FDISK_LIBRARIES) diff --git a/host-tools/genlittlefs/CMakeLists.txt b/host-tools/genlittlefs/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..11f524e690e0196dbca7da63c8bf6c5848e1a060 --- /dev/null +++ b/host-tools/genlittlefs/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.14) + +project(genlittlefs LANGUAGES C) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH}) + +find_package(BLKID REQUIRED) + +set(GENLITTLEFS_SRCS + mklfs.c + parse_partitions.c + parse_args.c + lfs_ioaccess.c +) + +add_executable(${PROJECT_NAME} ${GENLITTLEFS_SRCS}) +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -pedantic -Werror -Wextra ) +target_compile_definitions(${PROJECT_NAME} PRIVATE _GNU_SOURCE ) + +target_link_libraries(${PROJECT_NAME} PRIVATE littlefs ${BLKID_LIBRARIES}) +target_include_directories(${PROJECT_NAME} PRIVATE ${BLKID_INCLUDE_DIR}) + diff --git a/host-tools/genlittlefs/lfs_ioaccess.c b/host-tools/genlittlefs/lfs_ioaccess.c new file mode 100644 index 0000000000000000000000000000000000000000..61d542c83aaef4c15913d4773648e1487629d0d7 --- /dev/null +++ b/host-tools/genlittlefs/lfs_ioaccess.c @@ -0,0 +1,246 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "lfs.h" +#include "lfs_ioaccess.h" +#include "parse_partitions.h" + +#include +#include +#include +#include +#include +#include + +struct lfs_ioaccess_context +{ + int file_des; + loff_t part_offs; + size_t last_offs; + const void *empty_flash_mem; + struct timeval last_sync; +}; + +static int lfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) +{ + struct lfs_ioaccess_context *ctx = c->context; + if (!ctx) { + return LFS_ERR_IO; + } + const off_t offrq = (off_t)block * c->block_size + (off_t)off + ctx->part_offs; + if (offrq > (off_t)ctx->last_offs + size) { + return LFS_ERR_IO; + } + off_t err = lseek(ctx->file_des, offrq, SEEK_SET); + if (err < 0) { + return -errno; + } + else if (err != offrq) { + return LFS_ERR_IO; + } + char *rd_buf = buffer; + do { + ssize_t ret = read(ctx->file_des, rd_buf, (size_t)size); + if (ret > 0) { + size -= ret; + rd_buf += ret; + } + else if (ret == 0) { + break; + } + else { + return ret; + } + } while (size > 0); + return size > 0 ? LFS_ERR_IO : 0; +} + +static int lfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) +{ + struct lfs_ioaccess_context *ctx = c->context; + if (!ctx) { + return LFS_ERR_IO; + } + const off_t offrq = (off_t)block * c->block_size + (off_t)off + ctx->part_offs; + if (offrq > (off_t)ctx->last_offs + size) { + return LFS_ERR_IO; + } + off_t err = lseek(ctx->file_des, offrq, SEEK_SET); + if (err < 0) { + return -errno; + } + else if (err != offrq) { + return LFS_ERR_IO; + } + const char *wr_buf = buffer; + do { + ssize_t ret = write(ctx->file_des, wr_buf, (size_t)size); + if (ret > 0) { + size -= ret; + wr_buf += ret; + } + else if (ret == 0) { + break; + } + else { + return ret; + } + } while (size > 0); + return size > 0 ? LFS_ERR_IO : 0; +} + +static int lfs_erase(const struct lfs_config *c, lfs_block_t block) +{ + struct lfs_ioaccess_context *ctx = c->context; + if (!ctx) { + return LFS_ERR_IO; + } + const off_t offrq = (off_t)block * c->block_size + ctx->part_offs; + if (offrq > (off_t)ctx->last_offs + c->block_size) { + return LFS_ERR_IO; + } + off_t err = lseek(ctx->file_des, offrq, SEEK_SET); + if (err < 0) { + return -errno; + } + else if (err != offrq) { + return LFS_ERR_IO; + } + const char *wr_buf = ctx->empty_flash_mem; + size_t size; + do { + size = c->block_size; + ssize_t ret = write(ctx->file_des, wr_buf, (size_t)size); + if (ret > 0) { + size -= ret; + wr_buf += ret; + } + else if (ret == 0) { + break; + } + else { + return ret; + } + } while (size > 0); + return size > 0 ? LFS_ERR_IO : 0; +} + +static int lfs_sync(const struct lfs_config *c) +{ + struct lfs_ioaccess_context *ctx = c->context; + struct timeval curr_msync, result_msync; + if (gettimeofday(&curr_msync, NULL) == -1) { + return -1; + } + timersub(&curr_msync, &ctx->last_sync, &result_msync); + int err = 0; + if (result_msync.tv_sec >= 1) { + err = fsync(ctx->file_des); + ctx->last_sync = curr_msync; + } + return err; +} + +struct lfs_ioaccess_context *lfs_ioaccess_open(struct lfs_config *cfg, + const char *filename, + const struct partition *partition) +{ + struct lfs_ioaccess_context *ret = calloc(1, sizeof(struct lfs_ioaccess_context)); + if (!ret) { + return NULL; + } + { + char *memm = malloc(cfg->block_size); + if (!memm) { + free(ret); + return NULL; + } + memset(memm, 0xff, cfg->block_size); + ret->empty_flash_mem = memm; + } + ret->file_des = open(filename, O_RDWR); + if (ret->file_des < 0) { + free(ret); + return NULL; + } + struct stat statbuf; + int err = fstat(ret->file_des, &statbuf); + if (err < 0) { + close(ret->file_des); + free(ret); + return NULL; + } + off_t start_pos = 0; + ret->last_offs = statbuf.st_size; + if (partition) { + if (partition->end > statbuf.st_size) { + close(ret->file_des); + free(ret); + errno = E2BIG; + return NULL; + } + else { + start_pos = partition->start; + ret->last_offs = partition->end; + } + } + ret->part_offs = start_pos; + // Mount the file system + cfg->read = lfs_read; + cfg->prog = lfs_prog; + cfg->erase = lfs_erase; + cfg->sync = lfs_sync; + cfg->context = ret; + return ret; +} + +int lfs_ioaccess_close(struct lfs_ioaccess_context *ctx) +{ + if (!ctx) { + errno = EINVAL; + return -1; + } + free((void *)ctx->empty_flash_mem); + int ret = close(ctx->file_des); + free(ctx); + return ret; +} + +int lfs_ioaccess_is_lfs_filesystem(struct lfs_ioaccess_context *ctx) +{ + static const char lfs_id[] = "littlefs"; + static const size_t lfs_offs = 8U; + char buf[32]; + if (!ctx) { + errno = EINVAL; + return -1; + } + off_t offs = lseek(ctx->file_des, ctx->part_offs + lfs_offs, SEEK_SET); + if (offs < 0) { + return -1; + } + else if (offs != ctx->part_offs + (off_t)lfs_offs) { + errno = ERANGE; + return -1; + } + size_t rd_req = sizeof buf; + char *rd_buf = buf; + do { + ssize_t ret = read(ctx->file_des, rd_buf, rd_req); + if (ret > 0) { + rd_req -= ret; + rd_buf += ret; + } + else if (ret == 0) { + break; + } + else { + return ret; + } + } while (rd_req > 0); + if (rd_req) { + errno = ERANGE; + return -1; + } + return memcmp(buf, lfs_id, sizeof(lfs_id) - sizeof('\0')) == 0; +} diff --git a/host-tools/genlittlefs/lfs_ioaccess.h b/host-tools/genlittlefs/lfs_ioaccess.h new file mode 100644 index 0000000000000000000000000000000000000000..542dde99d80df83fb8e12e8528913bbfad7b4c76 --- /dev/null +++ b/host-tools/genlittlefs/lfs_ioaccess.h @@ -0,0 +1,17 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +struct lfs_config; +struct partition; + +struct lfs_ioaccess_context; + +struct lfs_ioaccess_context *lfs_ioaccess_open(struct lfs_config *cfg, + const char *filename, + const struct partition *partition); + +int lfs_ioaccess_close(struct lfs_ioaccess_context *ctx); + +int lfs_ioaccess_is_lfs_filesystem(struct lfs_ioaccess_context *ctx); diff --git a/host-tools/genlittlefs/mklfs.c b/host-tools/genlittlefs/mklfs.c new file mode 100644 index 0000000000000000000000000000000000000000..365f4c938d8e492d58dc6c1e30c85544a7d5428b --- /dev/null +++ b/host-tools/genlittlefs/mklfs.c @@ -0,0 +1,373 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "lfs.h" +#include "lfs_ioaccess.h" +#include "parse_partitions.h" +#include "parse_args.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct lfs_info_summary +{ + size_t files_added; + size_t directories_added; + size_t bytes_transferred; +}; + +static int create_dir_in_lfs(lfs_t *lfs, const char *lfs_path, bool verbose) +{ + int ret; + if (verbose) + fprintf(stdout, "[%s]\n", lfs_path); + if ((ret = lfs_mkdir(lfs, lfs_path)) < 0) { + fprintf(stderr, "can't create directory %s: error=%d\n", lfs_path, ret); + return ret; + } + return 0; +} + +static int create_file_in_lfs(lfs_t *lfs, const char *host_file, const char *lfs_file, bool verbose) +{ + int ret; + if (verbose) + fprintf(stdout, "%s\n", lfs_file); + // Open source file + int srcfd = open(host_file, O_RDONLY); + if (srcfd < 0) { + fprintf(stderr, "can't open source file %s: errno=%d (%s)\n", host_file, errno, strerror(errno)); + return -1; + } + + // Open destination file + lfs_file_t dstf; + if ((ret = lfs_file_open(lfs, &dstf, lfs_file, LFS_O_WRONLY | LFS_O_CREAT)) < 0) { + fprintf(stderr, "can't open destination file %s: error=%d\n", lfs_file, ret); + close(srcfd); + return ret; + } + do { + char copy_buffer[16384]; + ret = read(srcfd, copy_buffer, sizeof copy_buffer); + if (ret < 0) { + close(srcfd); + lfs_file_close(lfs, &dstf); + return ret; + } + else if (ret == 0) { + break; + } + char *lfs_wptr = copy_buffer; + int lfs_wrleft = ret; + do { + int retlfs = lfs_file_write(lfs, &dstf, lfs_wptr, lfs_wrleft); + if (retlfs <= 0) { + close(srcfd); + lfs_file_close(lfs, &dstf); + fprintf(stderr, "can't write to destination file %s: error=%d\n", lfs_file, retlfs); + return retlfs; + } + else { + lfs_wrleft -= retlfs; + lfs_wptr += retlfs; + } + } while (lfs_wrleft > 0); + + } while (ret > 0); + + // Close destination file + ret = lfs_file_close(lfs, &dstf); + if (ret < 0) { + fprintf(stderr, "can't close destination file %s: error=%d\n", lfs_file, ret); + close(srcfd); + return ret; + } + + // Close source file + close(srcfd); + return ret; +} + +static int add_directory_to_lfs( + lfs_t *lfs, const char *host_path, const char *lfs_path, struct lfs_info_summary *summary, bool verbose) +{ + DIR *dir; + struct dirent *ent; + char lfs_curr_path[PATH_MAX]; + char host_curr_path[PATH_MAX]; + int err = -1; + dir = opendir(host_path); + if (dir) { + while ((ent = readdir(dir))) { + // Skip . and .. directories + if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0)) { + // Update the current path + strcpy(lfs_curr_path, lfs_path); + strcat(lfs_curr_path, "/"); + strcat(lfs_curr_path, ent->d_name); + // Update native current path + strcpy(host_curr_path, host_path); + strcat(host_curr_path, "/"); + strcat(host_curr_path, ent->d_name); + + if (ent->d_type == DT_DIR) { + err = create_dir_in_lfs(lfs, lfs_curr_path, verbose); + if (err) { + closedir(dir); + return err; + } + else { + summary->directories_added++; + } + err = add_directory_to_lfs(lfs, host_curr_path, lfs_curr_path, summary, verbose); + if (err) { + closedir(dir); + return err; + } + } + else if (ent->d_type == DT_REG) { + err = create_file_in_lfs(lfs, host_curr_path, lfs_curr_path, verbose); + if (err) { + closedir(dir); + return err; + } + else { + summary->files_added++; + struct stat statbuf; + if (stat(host_curr_path, &statbuf) == 0) { + summary->bytes_transferred += statbuf.st_size; + } + } + } + } + } + closedir(dir); + } + return err; +} + +static int add_to_lfs(lfs_t *lfs, const char *dir, struct lfs_info_summary *summary, bool verbose) +{ + char *host_dir = canonicalize_file_name(dir); + bool is_dir, is_file; + off_t fsize; + { + struct stat stbuf; + int err = stat(host_dir, &stbuf); + if (err < 0) { + free(host_dir); + return -1; + } + fsize = stbuf.st_size; + is_dir = stbuf.st_mode & S_IFDIR; + is_file = stbuf.st_mode & S_IFREG; + } + if (!is_dir && !is_file) { + free(host_dir); + errno = ENOTDIR; + return -1; + } + char *sep_ptr = strrchr(host_dir, '/'); + char *tgt_dir = malloc(strlen(sep_ptr + 1) + sizeof('\0') + sizeof('/')); + if (!tgt_dir) { + free(host_dir); + errno = ENOMEM; + return -1; + } + else { + tgt_dir[0] = '/'; + strcpy(tgt_dir + 1, sep_ptr + 1); + } + int err; + if (is_dir) { + err = create_dir_in_lfs(lfs, tgt_dir, verbose); + if (err) { + free(host_dir); + free(tgt_dir); + return err; + } + err = add_directory_to_lfs(lfs, host_dir, tgt_dir, summary, verbose); + if (!err) { + summary->directories_added++; + } + } + else if (is_file) { + err = create_file_in_lfs(lfs, host_dir, tgt_dir, verbose); + if (!err) { + summary->files_added++; + summary->bytes_transferred += fsize; + } + } + free(host_dir); + free(tgt_dir); + return err; +} + +static void print_error(const char *str, int error) __attribute__((nonnull(1))); +static void print_error(const char *str, int error) +{ + if (error == -1) { + char buf[1024]; + fprintf(stderr, "system_error %s %s\n", str, strerror_r(errno, buf, sizeof buf)); + } + else { + fprintf(stderr, "lfs_error %s %i\n", str, error); + } +} + +static void configure_lfs_params(struct lfs_config *lfsc, const struct littlefs_opts *opts) + __attribute__((nonnull(1, 2))); + +static void configure_lfs_params(struct lfs_config *lfsc, const struct littlefs_opts *opts) +{ + memset(lfsc, 0, sizeof *lfsc); + lfsc->block_size = opts->block_size; + lfsc->read_size = opts->read_size; + lfsc->prog_size = opts->prog_size; + lfsc->lookahead_size = opts->lockahead_size; + lfsc->cache_size = opts->cache_size; + lfsc->block_cycles = opts->block_cycles; +} + +int main(int argc, char **argv) +{ + + int err; + struct littlefs_opts lopts; + struct lfs_config cfg; + struct lfs_info_summary prog_summary; + struct lfs_ioaccess_context *ioctx = NULL; + lfs_t lfs; + err = parse_program_args(argc, argv, &lopts); + if (err < 0) { + return err; + } + if (lopts.mode == littlefs_opts_listparts) { + size_t elems; + struct partition *parts = find_partitions(lopts.dst_image, scan_all_partitions, &elems); + print_partitions(parts, elems); + free(parts); + free(lopts.src_dirs); + return EXIT_SUCCESS; + } + + configure_lfs_params(&cfg, &lopts); + memset(&prog_summary, 0, sizeof(prog_summary)); + if (lopts.mode == littlefs_opts_parts) { + size_t elems; + struct partition *parts = find_partitions(lopts.dst_image, scan_all_partitions, &elems); + if (!parts) { + perror("Unable to list partitions:"); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + if (lopts.partition_num - 1 > (int)elems) { + fprintf(stderr, "Invalid partition selected. Max partition_num is: %lu\n", elems); + free(parts); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + const struct partition *curr_part = &parts[lopts.partition_num - 1]; + cfg.block_count = (curr_part->end - curr_part->start) / lopts.block_size; + ioctx = lfs_ioaccess_open(&cfg, lopts.dst_image, curr_part); + if (!ioctx) { + perror("Unable to open file:"); + free(parts); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + free(parts); + } + else if (lopts.mode == littlefs_opts_file) { + int fds = open(lopts.dst_image, O_CREAT | O_WRONLY, 0644); + if (fds < 0) { + perror("Unable to create file"); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + err = ftruncate(fds, lopts.filesystem_size); + if (err) { + perror("Unable to truncate file"); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + close(fds); + fds = -1; + cfg.block_count = lopts.filesystem_size / lopts.block_size; + ioctx = lfs_ioaccess_open(&cfg, lopts.dst_image, NULL); + if (!ioctx) { + perror("Unable to open file:"); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + } + else { + fprintf(stderr, "Unknown option\n"); + free(lopts.src_dirs); + lfs_ioaccess_close(ioctx); + return EXIT_FAILURE; + } + if (lopts.verbose) { + print_config_options(&lopts); + } + + if (!lopts.overwrite_existing && lfs_ioaccess_is_lfs_filesystem(ioctx) > 0) { + fprintf(stderr, "LFS filesystem already exists. If you want to overwrite add --overwrite flag\n"); + free(lopts.src_dirs); + lfs_ioaccess_close(ioctx); + return EXIT_FAILURE; + } + + err = lfs_format(&lfs, &cfg); + if (err < 0) { + fprintf(stderr, "lfs format error: error=%d\n", err); + lfs_ioaccess_close(ioctx); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + + err = lfs_mount(&lfs, &cfg); + if (err < 0) { + fprintf(stderr, "lfs mount error: error=%d\n", err); + lfs_ioaccess_close(ioctx); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + + for (size_t ndir = 0; ndir < lopts.src_dirs_siz; ++ndir) { + err = add_to_lfs(&lfs, lopts.src_dirs[ndir], &prog_summary, lopts.verbose); + if (err) { + print_error("Unable to open file:", err); + lfs_ioaccess_close(ioctx); + free(lopts.src_dirs); + lfs_unmount(&lfs); + return EXIT_FAILURE; + } + } + err = lfs_unmount(&lfs); + if (err < 0) { + fprintf(stderr, "lfs umount error: error=%d\n", err); + lfs_ioaccess_close(ioctx); + free(lopts.src_dirs); + return EXIT_FAILURE; + } + free(lopts.src_dirs); + lfs_ioaccess_close(ioctx); + printf("Littlefs summary:\n" + " Directories created: %lu, Files added: %lu, Transferred %lu kbytes.\n" + " Littlefs block size: %i blocks count: %i.\n", + prog_summary.directories_added, + prog_summary.files_added, + prog_summary.bytes_transferred / 1024UL, + cfg.block_size, + cfg.block_count); + return EXIT_SUCCESS; +} diff --git a/host-tools/genlittlefs/parse_args.c b/host-tools/genlittlefs/parse_args.c new file mode 100644 index 0000000000000000000000000000000000000000..030c9ce6cdaba02318053a5f74ffb194270bbab7 --- /dev/null +++ b/host-tools/genlittlefs/parse_args.c @@ -0,0 +1,331 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "parse_args.h" + +#include +#include +#include +#include +#include + +static int is_number(const char *s) +{ + const char *c = s; + + while (*c) { + if ((*c < '0') || (*c > '9')) { + return 0; + } + c++; + } + + return 1; +} + +static int is_hex(const char *s) +{ + const char *c = s; + + if (*c++ != '0') { + return 0; + } + + if (*c++ != 'x') { + return 0; + } + + while (*c) { + if (((*c < '0') || (*c > '9')) && ((*c < 'A') || (*c > 'F')) && ((*c < 'a') || (*c > 'f'))) { + return 0; + } + c++; + } + + return 1; +} + +static int to_int(const char *s) +{ + if (!s) { + return -1; + } + if (is_number(s)) { + return atoi(s); + } + else if (is_hex(s)) { + return (int)strtol(s, NULL, 16); + } + + return -1; +} + +static long long to_longlong(const char *s) +{ + if (!s) { + return -1; + } + if (is_number(s)) { + return atoll(s); + } + else if (is_hex(s)) { + return (long long)strtoll(s, NULL, 16); + } + return -1; +} + +static void usage(const char *name) __attribute__((nonnull(1))); +static void usage(const char *name) +{ + fprintf(stderr, "usage: %s [options] -- src_dir1 ... [src_dirN]\n", name); +} + +static void help(const char *name) __attribute__((nonnull(1))); +static void help(const char *name) +{ + static const char help_text[] = "usage: %s [options] -- src_dir1 ... [src_dirN]\n" + "\n" + "general options:\n" + " -h --help print help\n" + "\n" + "genlilttlefs options:\n" + " -i --image partition file image\n" + " -b --block_size logical block size, overrides the block device\n" + " -s --filesystem_size filesystem size when creating the new file\n" + " -p --partition_num partition number when use partitions (1-n)\n" + " -l --list_partitions list existing parition and numbers\n" + " --cache_size size of caches (block_size)\n" + " --read_size readable unit (block_size)\n" + " --prog_size programmable unit (block_size)\n" + " --lookahead_size size of lookahead buffer (8192)\n" + " --block_cycles number of erase cycles before eviction (512)\n" + " --overwrite reformat existing partition\n" + " --verbose verbose mode\n" + "\n" + "positional arguments:\n" + " src_dir1 first source directory\n" + " src_dirN N-th source directory\n"; + fprintf(stderr, help_text, name); +} + +int parse_program_args(int argc, char **argv, struct littlefs_opts *opts) +{ + int c; // Current option + int option_index = 0; + bool is_help = false; + bool is_listpart = false; + bool is_unknown = false; + static struct option long_options[] = { + {.name = "image", .has_arg = required_argument, .flag = 0, .val = 'i'}, + {.name = "block_size", .has_arg = required_argument, .flag = 0, .val = 'b'}, + {.name = "filesystem_size", .has_arg = required_argument, .flag = 0, .val = 's'}, + {.name = "partition_num", .has_arg = required_argument, .flag = 0, .val = 'p'}, + {.name = "list_partitions", .has_arg = no_argument, .flag = 0, .val = 'l'}, + {.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'}, + {.name = "read_size", .has_arg = required_argument, .flag = 0, .val = 0}, + {.name = "prog_size", .has_arg = required_argument, .flag = 0, .val = 0}, + {.name = "cache_size", .has_arg = required_argument, .flag = 0, .val = 0}, + {.name = "lockahead_size", .has_arg = required_argument, .flag = 0, .val = 0}, + {.name = "block_cycles", .has_arg = required_argument, .flag = 0, .val = 0}, + {.name = "overwrite", .has_arg = no_argument, .flag = 0, .val = 0}, + {.name = "verbose", .has_arg = no_argument, .flag = 0, .val = 0}, + {.name = 0, .has_arg = 0, .flag = 0, .val = 0}}; + memset(opts, 0, sizeof(*opts)); + while ((c = getopt_long(argc, argv, "i:b:s:p:lh", long_options, &option_index)) != -1) { + switch (c) { + case 0: + if (long_options[option_index].flag != 0) { + break; + } + const char *optname = long_options[option_index].name; + if (!strcmp(optname, "overwrite")) { + opts->overwrite_existing = true; + } + else if (!strcmp(optname, "verbose")) { + opts->verbose = true; + } + else if (!strcmp(optname, "block_cycles")) { + opts->block_cycles = to_int(optarg); + } + else if (!strcmp(optname, "lockahead_size")) { + opts->lockahead_size = to_int(optarg); + } + else if (!strcmp(optname, "cache_size")) { + opts->cache_size = to_int(optarg); + } + else if (!strcmp(optname, "prog_size")) { + opts->prog_size = to_int(optarg); + } + else if (!strcmp(optname, "read_size")) { + opts->read_size = to_int(optarg); + } + break; + case 'i': + opts->dst_image = optarg; + break; + case 'b': + opts->block_size = to_int(optarg); + break; + case 's': + opts->filesystem_size = to_longlong(optarg); + break; + case 'p': + opts->partition_num = to_int(optarg); + break; + case 'l': + is_listpart = true; + break; + case 'h': + is_help = true; + break; + default: + is_unknown = true; + break; + } + } + if (argc == 1) { + usage(argv[0]); + return -1; + } + else if (is_help) { + help(argv[0]); + return -1; + } + else if (is_unknown) { + fprintf(stderr, "Unknown option\n"); + return -1; + } + else if (is_listpart) { + opts->mode = littlefs_opts_listparts; + if (!opts->dst_image) { + fprintf(stderr, "--image is not specified\n"); + return -1; + } + else { + return 0; + } + } + else { + if (opts->block_cycles < 0) { + fprintf(stderr, "Warning: disable wear leveling\n"); + opts->block_cycles = -1; + } + else if (opts->block_cycles > 1000) { + fprintf(stderr, "Error: Maximum block cycles is 1000\n"); + return -1; + } + else if (opts->block_cycles == 0) { + opts->block_cycles = 512; + } + if (opts->block_size == 0) { + fprintf(stderr, "Missing --block_size argument\n"); + return -1; + } + else if (opts->block_size < 0) { + fprintf(stderr, "argument --block_size need to be > 0\n"); + return -1; + } + if (opts->read_size == 0) { + opts->read_size = opts->block_size; + } + else if (opts->read_size < 0) { + fprintf(stderr, "argument --read_size needs to be >0\n"); + return -1; + } + if (opts->prog_size == 0) { + opts->prog_size = opts->block_size; + } + else if (opts->prog_size < 0) { + fprintf(stderr, "argument --prog_size needs to be >0\n"); + return -1; + } + if (opts->cache_size == 0) { + opts->cache_size = opts->block_size; + } + else if (opts->cache_size < 0) { + fprintf(stderr, "argument --cache_size needs to be >0\n"); + return -1; + } + if (opts->lockahead_size == 0) { + opts->lockahead_size = 8192; + } + else if (opts->cache_size < 0) { + fprintf(stderr, "argument --lockahead_size needs to be >0\n"); + return -1; + } + if (!opts->dst_image) { + fprintf(stderr, "--image is not specified\n"); + return -1; + } + if (opts->filesystem_size < 0) { + fprintf(stderr, "argument --filesystem_size needs to be >0\n"); + return -1; + } + else if (opts->partition_num < 0) { + fprintf(stderr, "argument --partition_num needs to be >0\n"); + return -1; + } + else if (opts->filesystem_size == 0 && opts->partition_num == 0) { + fprintf(stderr, "Missing --filesystem_size or --partition_num \n"); + return -1; + } + else if (opts->filesystem_size > 0 && opts->partition_num > 0) { + fprintf(stderr, "Only --filesystem_size or --partition_num is allowed in same time"); + return -1; + } + else if (opts->filesystem_size > 0) { + if (opts->filesystem_size % opts->block_size) { + fprintf(stderr, "--filesystem_size should be multiply of block size\n"); + return -1; + } + opts->mode = littlefs_opts_file; + } + else if (opts->partition_num > 0) { + opts->mode = littlefs_opts_parts; + } + if (optind < argc) { + opts->src_dirs_siz = argc - optind; + opts->src_dirs = calloc(opts->src_dirs_siz, sizeof(char *)); + for (int i = 0; optind < argc; ++i) { + char *arg = argv[optind++]; + const size_t arg_sz = strlen(arg); + if (arg[arg_sz - 1] == '/') + arg[arg_sz - 1] = '\0'; + opts->src_dirs[i] = arg; + } + } + else { + fprintf(stderr, "source directories not specified\n"); + return -1; + } + if (!opts->dst_image) { + fprintf(stderr, "--image is not specified\n"); + return -1; + } + } + return 0; +} + +void print_config_options(const struct littlefs_opts *opts) +{ + static const char struct_info[] = "genlittlefs configuration:\n" + " LFS read size %i\n" + " LFS block size: %i\n" + " LFS prog size: %i\n" + " LFS cache size: %i\n" + " LFS lookahead size: %i\n" + " LFS block cycles: %i\n" + " Filesystem size: %lli\n" + " Partition number: %i\n" + " Overwrite existing fs: %i\n"; + printf(struct_info, + opts->read_size, + opts->block_size, + opts->prog_size, + opts->cache_size, + opts->lockahead_size, + opts->block_cycles, + opts->filesystem_size, + opts->partition_num, + opts->overwrite_existing); +} diff --git a/host-tools/genlittlefs/parse_args.h b/host-tools/genlittlefs/parse_args.h new file mode 100644 index 0000000000000000000000000000000000000000..d34e0cd00af612855fa0e6b3e037874c969d79e1 --- /dev/null +++ b/host-tools/genlittlefs/parse_args.h @@ -0,0 +1,36 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once +#include +#include + +enum littlefs_opts_mode +{ + littlefs_opts_listparts, + littlefs_opts_parts, + littlefs_opts_file +}; +struct littlefs_opts +{ + //! LFS config options + int read_size; //! Read size + int block_size; //! block size + int prog_size; //! Eraseable area size + int cache_size; //! Cache size + int lockahead_size; //! Lock ahead size + int block_cycles; //! Progam counter cycles + //! Other ars + enum littlefs_opts_mode mode; //! Software mode + long long filesystem_size; //! Filesystem size + int partition_num; //! Parition number + size_t src_dirs_siz; //! SOurce dirs size + char **src_dirs; //! Source directories + char *dst_image; //! Destination image + bool overwrite_existing; //! Overwrite existing format + bool verbose; //! Verbose mode +}; + +int parse_program_args(int argc, char **argv, struct littlefs_opts *opts) __attribute__((nonnull(3))); + +void print_config_options(const struct littlefs_opts *opts) __attribute__((nonnull(1))); diff --git a/host-tools/genlittlefs/parse_partitions.c b/host-tools/genlittlefs/parse_partitions.c new file mode 100644 index 0000000000000000000000000000000000000000..e59dfdfb11b4f15ae52b90c45180522638b586ce --- /dev/null +++ b/host-tools/genlittlefs/parse_partitions.c @@ -0,0 +1,63 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md +#include +#include "parse_partitions.h" +#include +#include +#include + +static const size_t sector_size = 512; + +struct partition *find_partitions(const char *filename, part_type_t ptype, size_t *nelems) +{ + struct partition *pret = NULL; + blkid_probe pr; + pr = blkid_new_probe_from_filename(filename); + if (!pr) { + return pret; + } + blkid_probe_enable_partitions(pr, true); + blkid_do_fullprobe(pr); + + blkid_partlist ls = blkid_probe_get_partitions(pr); + if (!ls) { + *nelems = 0; + return pret; + } + const int nparts = blkid_partlist_numof_partitions(ls); + if (nparts < 1) { + *nelems = 0; + return pret; + } + else { + pret = calloc(nparts, sizeof(struct partition)); + } + size_t ipart = 0; + for (int i = 0; i < nparts; ++i) { + blkid_partition par = blkid_partlist_get_partition(ls, i); + if (ptype == scan_all_partitions || blkid_partition_get_type(par) == ptype) { + pret[ipart].start = (blkid_partition_get_start(par)) * sector_size; + pret[ipart].end = (blkid_partition_get_start(par) + blkid_partition_get_size(par) - 1LLU) * sector_size; + pret[ipart].type = blkid_partition_get_type(par); + ++ipart; + } + *nelems = ipart; + } + blkid_free_probe(pr); + return pret; +} + +void print_partitions(const struct partition *part, size_t nparts) +{ + printf("List of partitions [%lu]:\n", nparts); + if (!part) { + return; + } + for (size_t s = 0; s < nparts; ++s) { + printf(" Number: [%lu] Type: [%02x] Start: [%luk] End: [%luk]\n", + s + 1, + (int)part->type, + part[s].start / 1024, + part[s].end / 1024); + } +} diff --git a/host-tools/genlittlefs/parse_partitions.h b/host-tools/genlittlefs/parse_partitions.h new file mode 100644 index 0000000000000000000000000000000000000000..ec098021abb17c4465fa8778b9444ebf6c73581c --- /dev/null +++ b/host-tools/genlittlefs/parse_partitions.h @@ -0,0 +1,24 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once +#include + +typedef int part_type_t; + +enum part_type_options +{ + scan_all_partitions = -1 +}; + +struct partition +{ + off_t start; + off_t end; + part_type_t type; +}; + +struct partition *find_partitions(const char *filename, part_type_t ptype, size_t *nelems) + __attribute__((nonnull(1, 3))); + +void print_partitions(const struct partition *part, size_t nparts); diff --git a/host-tools/littlefs-fuse/CMake/FindFUSE.cmake b/host-tools/littlefs-fuse/CMake/FindFUSE.cmake new file mode 100644 index 0000000000000000000000000000000000000000..12a9fca1354c5b59ece07890ffa45d452daee695 --- /dev/null +++ b/host-tools/littlefs-fuse/CMake/FindFUSE.cmake @@ -0,0 +1,34 @@ +# Find the FUSE includes and library +# +# FUSE_INCLUDE_DIR - where to find fuse.h, etc. +# FUSE_LIBRARIES - List of libraries when using FUSE. +# FUSE_FOUND - True if FUSE lib is found. + +# check if already in cache, be silent +IF (FUSE_INCLUDE_DIR) + SET (FUSE_FIND_QUIETLY TRUE) +ENDIF (FUSE_INCLUDE_DIR) + +# find includes +FIND_PATH (FUSE_INCLUDE_DIR fuse.h + /usr/local/include/osxfuse + /usr/local/include + /usr/include + ) + +# find lib +if (APPLE) + SET(FUSE_NAMES libosxfuse.dylib fuse) +else (APPLE) + SET(FUSE_NAMES fuse) +endif (APPLE) +FIND_LIBRARY(FUSE_LIBRARIES + NAMES ${FUSE_NAMES} + PATHS /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /usr/lib/x86_64-linux-gnu + ) + +include ("FindPackageHandleStandardArgs") +find_package_handle_standard_args ("FUSE" DEFAULT_MSG + FUSE_INCLUDE_DIR FUSE_LIBRARIES) + +mark_as_advanced (FUSE_INCLUDE_DIR FUSE_LIBRARIES) diff --git a/host-tools/littlefs-fuse/CMakeLists.txt b/host-tools/littlefs-fuse/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6317c1e6855f448bd2ae1d810386558d4c4451ce --- /dev/null +++ b/host-tools/littlefs-fuse/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.14) + +project(lfsfuse LANGUAGES C) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH}) + +find_package(FUSE REQUIRED) + +file(GLOB_RECURSE LFSFUSE_SRCS *.c) +add_executable(${PROJECT_NAME} ${LFSFUSE_SRCS}) + + +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -pedantic) +target_compile_definitions( ${PROJECT_NAME} + PRIVATE + _FILE_OFFSET_BITS=64 + _XOPEN_SOURCE=700 + LFS_MIGRATE +) + +target_include_directories( ${PROJECT_NAME} + PRIVATE + lfsfuse/littlefs + ${FUSE_INCLUDE_DIR} +) + +target_link_libraries( ${PROJECT_NAME} ${FUSE_LIBRARIES} ) diff --git a/host-tools/littlefs-fuse/lfsfuse b/host-tools/littlefs-fuse/lfsfuse new file mode 160000 index 0000000000000000000000000000000000000000..ccb30b35edf32cea35bf09cfbfc6b9f6e5f1d930 --- /dev/null +++ b/host-tools/littlefs-fuse/lfsfuse @@ -0,0 +1 @@ +Subproject commit ccb30b35edf32cea35bf09cfbfc6b9f6e5f1d930 diff --git a/module-vfs/CMakeLists.txt b/module-vfs/CMakeLists.txt index 512eed9b75265db92beb66c98f90ad731f5b67f7..b84d5a1c1ebba297f9e7b739753420c4254e2334 100644 --- a/module-vfs/CMakeLists.txt +++ b/module-vfs/CMakeLists.txt @@ -1,10 +1,12 @@ cmake_minimum_required(VERSION 3.12) include(thirdparty) -include(thirdparty/littlefs.cmake) + project(module-vfs VERSION 1.0 DESCRIPTION "VFS module library") +add_subdirectory(thirdparty/lfsfs) + set(FREERTOS_FAT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/board/freeRTOS_FAT/ff_crc.c ${CMAKE_CURRENT_SOURCE_DIR}/board/freeRTOS_FAT/ff_dir.c diff --git a/module-vfs/thirdparty/littlefs.cmake b/module-vfs/thirdparty/lfsfs/CMakeLists.txt similarity index 56% rename from module-vfs/thirdparty/littlefs.cmake rename to module-vfs/thirdparty/lfsfs/CMakeLists.txt index 922ad2c604c6208a03dc3c59d8fc3e16603b1470..62b302334e848ca3fb361b147ccd969949ed2a2c 100644 --- a/module-vfs/thirdparty/littlefs.cmake +++ b/module-vfs/thirdparty/lfsfs/CMakeLists.txt @@ -1,9 +1,11 @@ -include(thirdparty) +cmake_minimum_required(VERSION 3.14) -set(LIBLITTLEFS_TARGET littlefs) +project(littlefs LANGUAGES C) +include(thirdparty OPTIONAL) -set(LIBLITTLEFS_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/littlefs) +set(LIBLITTLEFS_SRCDIR littlefs) +set(LIBLITTLEFS_TARGET ${PROJECT_NAME}) set(LIBLITTLEFS_SOURCES ${LIBLITTLEFS_SRCDIR}/lfs.c @@ -18,7 +20,12 @@ set( LIBLITTLEFS_PRIVATE_INCLUDES ${LIBLITTLEFS_SRCDIR}/bd) add_library( ${LIBLITTLEFS_TARGET} STATIC ${LIBLITTLEFS_SOURCES} ) -third_party_target_setup( ${LIBLITTLEFS_TARGET} ) + +#target_compile_definitions(${LIBLITTLEFS_TARGET} PRIVATE LFS_YES_TRACE ) + +if( COMMAND third_party_target_setup ) + third_party_target_setup( ${LIBLITTLEFS_TARGET} ) +endif() target_include_directories( ${LIBLITTLEFS_TARGET} PUBLIC @@ -26,5 +33,6 @@ target_include_directories( ${LIBLITTLEFS_TARGET} PRIVATE ${LIBLITTLEFS_PRIVATE_INCLUDES} ) - -third_party_source_optimization( ${LIBLITTLEFS_SOURCES} ) +if( COMMAND third_party_source_optimization ) + third_party_source_optimization( ${LIBLITTLEFS_SOURCES} ) +endif() diff --git a/module-vfs/thirdparty/lfsfs/littlefs b/module-vfs/thirdparty/lfsfs/littlefs new file mode 160000 index 0000000000000000000000000000000000000000..1a59954ec64ca168828a15242cc6de94ac75f9d1 --- /dev/null +++ b/module-vfs/thirdparty/lfsfs/littlefs @@ -0,0 +1 @@ +Subproject commit 1a59954ec64ca168828a15242cc6de94ac75f9d1 diff --git a/module-vfs/thirdparty/littlefs b/module-vfs/thirdparty/littlefs deleted file mode 160000 index 4c9146ea539f72749d6cc3ea076372a81b12cb11..0000000000000000000000000000000000000000 --- a/module-vfs/thirdparty/littlefs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4c9146ea539f72749d6cc3ea076372a81b12cb11