/* * Copyright (C) 2015 - 2020, IBEROXARXA SERVICIOS INTEGRALES, S.L. * Copyright (C) 2015 - 2020, Jaume Olivé Petrus (jolive@whitecatboard.org) * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * The WHITECAT logotype cannot be changed, you can remove it, but you * cannot change it in any way. The WHITECAT logotype is: * * /\ /\ * / \_____/ \ * /_____________\ * W H I T E C A T * * * Redistributions in binary form must retain all copyright notices printed * to any local or remote output device. This include any reference to * Lua RTOS, whitecatboard.org, Lua, and other copyright notices that may * appear in the future. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Lua RTOS, a tool for make a LFS file system image * */ #include "lfs.h" #include #include #include #include #include #include #include #include #include static struct lfs_config cfg; static lfs_t lfs; static uint8_t *data; static int lfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { memcpy(buffer, data + (block * c->block_size) + off, size); return 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) { memcpy(data + (block * c->block_size) + off, buffer, size); return 0; } static int lfs_erase(const struct lfs_config *c, lfs_block_t block) { memset(data + (block * c->block_size), 0, c->block_size); return 0; } static int lfs_sync(const struct lfs_config *c) { return 0; } static void create_dir(char *src) { char *path; path = strchr(src, '/'); if (path) { int ret; fprintf(stdout, "%s\r\n", path); if ((ret = lfs_mkdir(&lfs, path)) < 0) { fprintf(stderr, "can't create directory %s: error=%d\r\n", path, ret); exit(1); } } } static void create_file(char *src) { char *path; path = strchr(src, '/'); if (path) { fprintf(stdout, "%s\r\n", path); // Open source file FILE *srcf = fopen(src, "rb"); if (!srcf) { fprintf(stderr, "can't open source file %s: errno=%d (%s)\r\n", src, errno, strerror(errno)); exit(1); } // Open destination file lfs_file_t dstf; int ret; if ((ret = lfs_file_open(&lfs, &dstf, path, LFS_O_WRONLY | LFS_O_CREAT)) < 0) { fprintf(stderr, "can't open destination file %s: error=%d\r\n", path, ret); exit(1); } char c = fgetc(srcf); while (!feof(srcf)) { ret = lfs_file_write(&lfs, &dstf, &c, 1); if (ret < 0) { fprintf(stderr, "can't write to destination file %s: error=%d\r\n", path, ret); exit(1); } c = fgetc(srcf); } // Close destination file ret = lfs_file_close(&lfs, &dstf); if (ret < 0) { fprintf(stderr, "can't close destination file %s: error=%d\r\n", path, ret); exit(1); } // Close source file fclose(srcf); } } static void skip_direct(char *curr_path, struct dirent *ent, char *src); static void compact(char *src) { DIR *dir; dir = opendir(src); if (dir) { struct dirent *ent; char curr_path[PATH_MAX]; while ((ent = readdir(dir))) { // Skip . and .. directories skip_direct(curr_path, ent, src); } closedir(dir); } } static void skip_direct(char *curr_path, struct dirent *ent, char *src) { if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0)) { // Update the current path strcpy(curr_path, src); strcat(curr_path, "/"); strcat(curr_path, ent->d_name); if (ent->d_type == DT_DIR) { create_dir(curr_path); compact(curr_path); } else if (ent->d_type == DT_REG) { create_file(curr_path); } } } void usage(void) { (void)fprintf(stdout, "usage: mklfs -c -b -r -p -s -n " " -l -e -k -i \r\n"); } 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 (is_number(s)) { return atoi(s); } else if (is_hex(s)) { return (int)strtol(s, NULL, 0x10); } return -1; } int main(int argc, char **argv) { char *src = NULL; // Source directory char *dst = NULL; // Destination image int c; // Current option int block_size = 0; // Block size int read_size = 0; // Read size int prog_size = 0; // Prog size int fs_size = 0; // File system size int err; int part_no = 0; // context int blk_cycles = 0; // block_cycles int la_size = 0; // lookahead_size int ca_size = 0; // cache_size while ((c = getopt(argc, argv, "c:i:b:p:r:s:n:l:e:k:")) != -1) { switch (c) { case 'c': src = optarg; break; case 'i': dst = optarg; break; case 'b': block_size = to_int(optarg); break; case 'p': prog_size = to_int(optarg); break; case 'r': read_size = to_int(optarg); break; case 's': fs_size = to_int(optarg); break; case 'n': part_no = to_int(optarg); break; case 'l': la_size = to_int(optarg); break; case 'e': ca_size = to_int(optarg); break; case 'k': blk_cycles = to_int(optarg); break; default: break; } } if ((src == NULL) || (dst == NULL) || (block_size <= 0) || (prog_size <= 0) || (read_size <= 0) || (fs_size <= 0)) { usage(); exit(1); } // Mount the file system cfg.read = lfs_read; cfg.prog = lfs_prog; cfg.erase = lfs_erase; cfg.sync = lfs_sync; cfg.block_size = block_size; cfg.read_size = read_size; cfg.prog_size = prog_size; cfg.block_count = fs_size / cfg.block_size; cfg.lookahead_size = la_size; cfg.context = (void *)part_no; cfg.block_cycles = blk_cycles; cfg.cache_size = ca_size; data = calloc(1, fs_size); if (!data) { fprintf(stderr, "no memory for mount\r\n"); return -1; } err = lfs_format(&lfs, &cfg); if (err < 0) { fprintf(stderr, "format error: error=%d\r\n", err); return -1; } err = lfs_mount(&lfs, &cfg); if (err < 0) { fprintf(stderr, "mount error: error=%d\r\n", err); return -1; } char *last_dir = strrchr(src, '/'); if (last_dir) { last_dir++; compact(last_dir); } else { compact(src); } FILE *img = fopen(dst, "wb+"); if (!img) { fprintf(stderr, "can't create image file: errno=%d (%s)\r\n", errno, strerror(errno)); return -1; } int ret; ret = fwrite(data, 1, fs_size, img); if (ret < 0) { fprintf(stderr, "fwrite(data, 1, fs_size, img): errno=%d (%s)\r\n", errno, strerror(errno)); } ret = fclose(img); if (ret < 0) { fprintf(stderr, "fclose(img): errno=%d (%s)\r\n", errno, strerror(errno)); return -1; } return 0; }