From 5a6992c26a45a730edb2fff828e1edba16ef858d Mon Sep 17 00:00:00 2001 From: ziggurat29 <30310677+ziggurat29@users.noreply.github.com> Date: Tue, 9 Apr 2019 08:38:49 -0500 Subject: [PATCH] added spiffsimg host tools project to msvc build configuration. (#2686) --- app/spiffs/spiffs_nucleus.h | 12 + msvc/hosttools.sln | 10 + msvc/spiffsimg/getopt.h | 651 +++++++++++++++ msvc/spiffsimg/spiffsimg.vcxproj | 207 +++++ msvc/spiffsimg/spiffsimg.vcxproj.filters | 81 ++ tools/spiffsimg/main.c | 957 ++++++++++++----------- tools/spiffsimg/spiffs_typedefs.h | 2 +- 7 files changed, 1463 insertions(+), 457 deletions(-) create mode 100644 msvc/spiffsimg/getopt.h create mode 100644 msvc/spiffsimg/spiffsimg.vcxproj create mode 100644 msvc/spiffsimg/spiffsimg.vcxproj.filters diff --git a/app/spiffs/spiffs_nucleus.h b/app/spiffs/spiffs_nucleus.h index 2b03b8c9..c4a0729b 100644 --- a/app/spiffs/spiffs_nucleus.h +++ b/app/spiffs/spiffs_nucleus.h @@ -476,6 +476,9 @@ typedef struct { // object structs +#ifdef _MSC_VER +#pragma pack ( push, 1 ) +#endif // page header, part of each page except object lookup pages // NB: this is always aligned when the data page is an object index, @@ -492,8 +495,13 @@ typedef struct SPIFFS_PACKED { // object index header page header typedef struct SPIFFS_PACKED #if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#ifdef _MSC_VER +//Note: the following needs to track the sizeof(spiffs_page_ix), which is defined in spiffs_config.h + __declspec( align( 2 ) ) +#else __attribute(( aligned(sizeof(spiffs_page_ix)) )) #endif +#endif { // common page header spiffs_page_header p_hdr; @@ -517,6 +525,10 @@ typedef struct SPIFFS_PACKED { u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))]; } spiffs_page_object_ix; +#ifdef _MSC_VER +#pragma pack ( pop ) +#endif + // callback func for object lookup visitor typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, const void *user_const_p, void *user_var_p); diff --git a/msvc/hosttools.sln b/msvc/hosttools.sln index 30f55e26..75514eea 100644 --- a/msvc/hosttools.sln +++ b/msvc/hosttools.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.28307.168 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luac-cross", "luac-cross\luac-cross.vcxproj", "{78A3411A-A18F-41A4-B4A7-D76B273F0E44}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spiffsimg", "spiffsimg\spiffsimg.vcxproj", "{2DD84C09-254C-4884-A863-456EA1E32DCE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -21,6 +23,14 @@ Global {78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x64.Build.0 = Release|x64 {78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x86.ActiveCfg = Release|Win32 {78A3411A-A18F-41A4-B4A7-D76B273F0E44}.Release|x86.Build.0 = Release|Win32 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x64.ActiveCfg = Debug|x64 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x64.Build.0 = Debug|x64 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x86.ActiveCfg = Debug|Win32 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Debug|x86.Build.0 = Debug|Win32 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x64.ActiveCfg = Release|x64 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x64.Build.0 = Release|x64 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x86.ActiveCfg = Release|Win32 + {2DD84C09-254C-4884-A863-456EA1E32DCE}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/msvc/spiffsimg/getopt.h b/msvc/spiffsimg/getopt.h new file mode 100644 index 00000000..520cc6a1 --- /dev/null +++ b/msvc/spiffsimg/getopt.h @@ -0,0 +1,651 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + /* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +//extern int optind; /* index of first non-option in argv */ +//extern int optopt; /* single option character, as parsed */ +//extern int opterr; /* flag to enable built-in diagnostics... */ +// /* (user may set to zero, to suppress) */ +// +//extern char *optarg; /* pointer to argument of current option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) *__progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void +_vwarnx(const char *fmt,va_list ap) +{ + (void)fprintf(stderr,"%s: ",__progname); + if (fmt != NULL) + (void)vfprintf(stderr,fmt,ap); + (void)fprintf(stderr,"\n"); +} + +static void +warnx(const char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + _vwarnx(fmt,ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +//extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = (char*)strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} + +//extern int getopt_long(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +//extern int getopt_long_only(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ diff --git a/msvc/spiffsimg/spiffsimg.vcxproj b/msvc/spiffsimg/spiffsimg.vcxproj new file mode 100644 index 00000000..3927d900 --- /dev/null +++ b/msvc/spiffsimg/spiffsimg.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {2DD84C09-254C-4884-A863-456EA1E32DCE} + Win32Proj + spiffsimg + 7.0 + + + + Application + true + v141_xp + MultiByte + + + Application + false + v141_xp + true + MultiByte + + + Application + true + v141_xp + MultiByte + + + Application + false + v141_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(ProjectDir)$(Platform)\$(Configuration)\ + + + true + $(ProjectDir)$(Platform)\$(Configuration)\ + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(ProjectDir)$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)$(Platform)\$(Configuration)\ + $(ProjectDir)$(Platform)\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + true + NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions) + true + pch.h + MultiThreadedDebug + $(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir) + $(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles) + + + Console + true + true + setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + true + NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;_DEBUG;WIN32;%(PreprocessorDefinitions) + true + pch.h + MultiThreadedDebug + $(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir) + $(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles) + + + Console + true + true + setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions) + true + pch.h + MultiThreaded + $(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir) + $(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles) + + + Console + true + true + true + true + setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NODEMCU_SPIFFS_NO_INCLUDE;dbg_printf=printf;_CRT_SECURE_NO_WARNINGS;_CONSOLE;NDEBUG;WIN32;%(PreprocessorDefinitions) + true + pch.h + MultiThreaded + $(ProjectDir)\..\..\app\include;$(ProjectDir)\..\..\app\spiffs;$(ProjectDir) + $(ProjectDir)\..\..\tools\spiffsimg\spiffs_typedefs.h;%(ForcedIncludeFiles) + + + Console + true + true + true + true + setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + 4996 + 4996 + 4996 + 4996 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msvc/spiffsimg/spiffsimg.vcxproj.filters b/msvc/spiffsimg/spiffsimg.vcxproj.filters new file mode 100644 index 00000000..bbf3b230 --- /dev/null +++ b/msvc/spiffsimg/spiffsimg.vcxproj.filters @@ -0,0 +1,81 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {cc72cbf7-30a4-4c62-9413-509516a67c12} + + + {2796bdda-1fd8-4088-8d4e-41fdd71d5170} + + + {ba2fdaa9-bc69-4fb5-b789-9d2b46d7fd31} + + + {d6547699-189a-45e8-82d8-4af0a0b4cfd7} + + + {131db3e8-d55b-4d0a-810b-ae33c5e41bb3} + + + {184f25b5-aca7-476f-981f-16d7a8294ca7} + + + + + tools\spiffsimg + + + app\spiffs + + + app\spiffs + + + app\spiffs + + + app\spiffs + + + app\spiffs + + + + + tools\spiffsimg + + + app\spiffs + + + app\spiffs + + + app\spiffs + + + app\spiffs + + + app\include + + + app\platform + + + Header Files + + + \ No newline at end of file diff --git a/tools/spiffsimg/main.c b/tools/spiffsimg/main.c index c6f6985f..d62234e2 100644 --- a/tools/spiffsimg/main.c +++ b/tools/spiffsimg/main.c @@ -1,456 +1,501 @@ -/* - * Copyright 2015 Dius Computing Pty Ltd. 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 copyright holders nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 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 - * THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. - * - * @author Johny Mattsson - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "spiffs.h" -#define NO_CPU_ESP8266_INCLUDE -#include "../platform/cpu_esp8266.h" - -static spiffs fs; -static uint8_t *flash; - -static int retcode = 0; - -#define LOG_PAGE_SIZE 256 - -// If the caclulated size is this or less, then use smaller blocks -// (1 page) rather than the normal 2 pages. This gives a little bit -// more flexibility for the file system, at the expense of a bit of -// efficiency -#define SMALL_FILESYSTEM (128 * 1024) - -static int delete_on_die = 0; -static const char *delete_list[10]; -static int delete_list_index = 0; - -static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2]; -static u8_t spiffs_fds[32*4]; - -static s32_t flash_read (u32_t addr, u32_t size, u8_t *dst) { - memcpy (dst, flash + addr, size); - return SPIFFS_OK; -} - -static s32_t flash_write (u32_t addr, u32_t size, u8_t *src) { - memcpy (flash + addr, src, size); - return SPIFFS_OK; -} - -static s32_t flash_erase (u32_t addr, u32_t size) { - memset (flash + addr, 0xff, size); - return SPIFFS_OK; -} - - -static void die (const char *what) -{ - if (errno == 0) { - fprintf(stderr, "%s: fatal error\n", what); - } else { - perror (what); - } - if (delete_on_die) { - const char **p = delete_list; - while (*p) { - unlink(*p); - p++; - } - } - exit (1); -} - - -static void list (void) -{ - spiffs_DIR dir; - if (!SPIFFS_opendir (&fs, "/", &dir)) - die ("spiffs_opendir"); - struct spiffs_dirent de; - while (SPIFFS_readdir (&dir, &de)) - { - static const char types[] = "?fdhs"; // file, dir, hardlink, softlink - char name[sizeof(de.name)+1] = { 0 }; - memcpy (name, de.name, sizeof(de.name)); - printf("%c %6u %s\n", types[de.type], de.size, name); - } - SPIFFS_closedir (&dir); -} - - -static void cat (char *fname) -{ - spiffs_file fh = SPIFFS_open (&fs, fname, SPIFFS_RDONLY, 0); - char buff[512]; - s32_t n; - while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0) - write (STDOUT_FILENO, buff, n); - SPIFFS_close (&fs, fh); -} - - -static void import (char *src, char *dst) -{ - int fd = open (src, O_RDONLY); - if (fd < 0) - die (src); - - spiffs_file fh = SPIFFS_open (&fs, dst, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); - if (fh < 0) - die ("spiffs_open"); - - char buff[16384]; - s32_t n; - while ((n = read (fd, buff, sizeof (buff))) > 0) - if (SPIFFS_write (&fs, fh, buff, n) < 0) - die ("spiffs_write"); - - if (SPIFFS_close (&fs, fh) < 0) - die("spiffs_close"); - close (fd); -} - - -static void export (char *src, char *dst) -{ - spiffs_file fh = SPIFFS_open (&fs, src, SPIFFS_RDONLY, 0); - if (fh < 0) - die ("spiffs_open"); - - int fd = open (dst, O_CREAT | O_TRUNC | O_WRONLY, 0664); - if (fd < 0) - die (dst); - - char buff[512]; - s32_t n; - while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0) - if (write (fd, buff, n) < 0) - die ("write"); - - SPIFFS_close (&fs, fh); - close (fd); -} - - -char *trim (char *in) -{ - if (!in) - return ""; - - char *out = 0; - while (*in) - { - if (!out && !isspace (*in)) - out = in; - ++in; - } - if (!out) - return ""; - while (--in > out && isspace (*in)) - ; - in[1] = 0; - return out; -} - - -void syntax (void) -{ - fprintf (stderr, - "Syntax: spiffsimg -f [-d] [-o ] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r ]\n\n" - ); - exit (1); -} - -static size_t getsize(const char *s) -{ - char *end = 0; - size_t val = strtoul(s, &end, 0); - - if (end) { - int factor; - if (*end == 'k' || *end == 'K') { - factor = 1 << 10; - end++; - } else if (*end == 'm' || *end == 'M') { - factor = 1 << 20; - end++; - } else { - factor = 1; - } - // Capital B is bytes - if (*end == 'B') { - factor = factor << 3; - } - // we want bytes - val = (val * factor) / 8; - } - - return val; -} - -int main (int argc, char *argv[]) -{ - if (argc == 1) - syntax (); - - int opt; - const char *fname = 0; - bool create = false; - enum { CMD_NONE, CMD_LIST, CMD_INTERACTIVE, CMD_SCRIPT } command = CMD_NONE; - int sz = 0; - const char *script_name = 0; - const char *resolved = 0; - int flashsize = 0; - int used = 0; - while ((opt = getopt (argc, argv, "do:f:c:lir:S:U:")) != -1) - { - switch (opt) - { - case 'f': fname = optarg; break; - case 'o': resolved = optarg; break; - case 'c': create = true; sz = strtol(optarg, 0, 0); break; - case 'S': create = true; flashsize = getsize(optarg); break; - case 'U': create = true; used = strtol(optarg, 0, 0); break; - case 'd': delete_on_die = 1; break; - case 'l': command = CMD_LIST; break; - case 'i': command = CMD_INTERACTIVE; break; - case 'r': command = CMD_SCRIPT; script_name = optarg; break; - default: die ("unknown option"); - } - } - - if (!fname) { - die("Need a filename"); - } - - int fd; - - if (create) - { - if (!sz) { - if (!flashsize || !used) { - die("Missing flashSize or Used"); - } - sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096; // This leaves space for the parameter area - if (sz < 0x4000) { - die("Not enough space"); - } - if (sz > SMALL_FILESYSTEM) { - used = (used + 0xffff) & ~0xffff; - } else { - used = (used + 0x1fff) & ~0x1fff; - } - sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096; - } - sz &= ~(0x1fff); - - if (used == 0) { - if (strchr(fname, '%')) { - die("Unable to calculate where to put the flash image, and % present in filename"); - } - } - - char fnamebuff[1024]; - - sprintf(fnamebuff, fname, used); - - delete_list[delete_list_index++] = strdup(fnamebuff);; - fd = open (fnamebuff, (create ? (O_CREAT | O_TRUNC) : 0) | O_RDWR, 0664); - if (fd == -1) - die ("open"); - - if (resolved) { - delete_list[delete_list_index++] = resolved; - FILE *f = fopen(resolved, "w"); - fprintf(f, "0x%x", used); - fclose(f); - } - - if (lseek (fd, sz -1, SEEK_SET) == -1) - die ("lseek"); - if (write (fd, "", 1) != 1) - die ("write"); - } - else { - fd = open (fname, O_RDWR, 0664); - if (fd == -1) - die ("open"); - - if (!sz) - { - off_t offs = lseek (fd, 0, SEEK_END); - if (offs == -1) - die ("lseek"); - sz = offs; - } - } - - if (sz & (0x1000 -1)) - die ("file size not multiple of erase block size"); - - flash = mmap (0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (!flash) - die ("mmap"); - - if (create) - memset (flash, 0xff, sz); - - spiffs_config cfg; - cfg.phys_size = sz; - cfg.phys_addr = 0; - cfg.phys_erase_block = 0x1000; - cfg.log_block_size = 0x1000 * (sz > SMALL_FILESYSTEM ? 2 : 1); - cfg.log_page_size = LOG_PAGE_SIZE; - cfg.hal_read_f = flash_read; - cfg.hal_write_f = flash_write; - cfg.hal_erase_f = flash_erase; - if (cfg.phys_size < 4 * cfg.log_block_size) { - die("disk not large enough for four blocks"); - } - - if (SPIFFS_mount (&fs, &cfg, - spiffs_work_buf, - spiffs_fds, - sizeof(spiffs_fds), - malloc(65536), 65536, 0) != 0) { - if (create) { - if (SPIFFS_format(&fs) != 0) { - die("spiffs_format"); - } - if (SPIFFS_mount (&fs, &cfg, - spiffs_work_buf, - spiffs_fds, - sizeof(spiffs_fds), - malloc(65536), 65536, 0) != 0) { - die ("spiffs_mount"); - } - if (command == CMD_INTERACTIVE) { - printf("Created filesystem -- size 0x%x, block_size=%d\n", cfg.phys_size, cfg.log_block_size); - } - } else { - die ("spiffs_mount"); - } - } - - if (command == CMD_NONE) - ; // maybe just wanted to create an empty image? - else if (command == CMD_LIST) - list (); - else - { - FILE *in = (command == CMD_INTERACTIVE) ? stdin : fopen (script_name, "r"); - if (!in) - die ("fopen"); - char buff[128] = { 0 }; - if (in == stdin) - printf("> "); - while (fgets (buff, sizeof (buff) -1, in)) - { - char *line = trim (buff); - if (!line[0] || line[0] == '#') - continue; - if (strcmp (line, "ls") == 0) - list (); - else if (strncmp (line, "import ", 7) == 0) - { - char *src = 0, *dst = 0; - if (sscanf (line +7, " %ms %ms", &src, &dst) != 2) - { - fprintf (stderr, "SYNTAX ERROR: %s\n", line); - retcode = 1; - } - else - import (src, dst); - free (src); - free (dst); - } - else if (strncmp (line, "export ", 7) == 0) - { - char *src = 0, *dst = 0; - if (sscanf (line + 7, " %ms %ms", &src, &dst) != 2) - { - fprintf (stderr, "SYNTAX ERROR: %s\n", line); - retcode = 1; - } - else - export (src, dst); - free (src); - free (dst); - } - else if (strncmp (line, "rm ", 3) == 0) - { - if (SPIFFS_remove (&fs, trim (line + 3)) < 0) - { - fprintf (stderr, "FAILED: %s\n", line); - retcode = 1; - } - } - else if (strncmp (line, "cat ", 4) == 0) - cat (trim (line + 4)); - else if (strncmp (line, "info", 4) == 0) - { - u32_t total, used; - if (SPIFFS_info (&fs, &total, &used) < 0) - { - fprintf (stderr, "FAILED: %s\n", line); - retcode = 1; - } - else - printf ("Total: %u, Used: %u\n", total, used); - } - else - { - printf ("SYNTAX ERROR: %s\n", line); - retcode = 1; - } - - if (in == stdin) - printf ("> "); - } - if (in == stdin) - printf ("\n"); - } - - SPIFFS_unmount (&fs); - munmap (flash, sz); - close (fd); - return retcode; -} +/* + * Copyright 2015 Dius Computing Pty Ltd. 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 copyright holders nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 + * THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + * + * @author Johny Mattsson + */ + +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include "getopt.h" /* local copy from MingW project */ +#include +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +typedef ptrdiff_t off_t; +#else +#include +#include +#include +#endif +#include +#include +#include "spiffs.h" +#define NO_CPU_ESP8266_INCLUDE +#include "../platform/cpu_esp8266.h" + +static spiffs fs; +static uint8_t *flash; + +static int retcode = 0; + +#define LOG_PAGE_SIZE 256 + +// If the caclulated size is this or less, then use smaller blocks +// (1 page) rather than the normal 2 pages. This gives a little bit +// more flexibility for the file system, at the expense of a bit of +// efficiency +#define SMALL_FILESYSTEM (128 * 1024) + +static int delete_on_die = 0; +static const char *delete_list[10]; +static int delete_list_index = 0; + +static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2]; +static u8_t spiffs_fds[32*4]; + +static s32_t flash_read (u32_t addr, u32_t size, u8_t *dst) { + memcpy (dst, flash + addr, size); + return SPIFFS_OK; +} + +static s32_t flash_write (u32_t addr, u32_t size, u8_t *src) { + memcpy (flash + addr, src, size); + return SPIFFS_OK; +} + +static s32_t flash_erase (u32_t addr, u32_t size) { + memset (flash + addr, 0xff, size); + return SPIFFS_OK; +} + + +static void die (const char *what) +{ + if (errno == 0) { + fprintf(stderr, "%s: fatal error\n", what); + } else { + perror (what); + } + if (delete_on_die) { + const char **p = delete_list; + while (*p) { + unlink(*p); + p++; + } + } + exit (1); +} + + +static void list (void) +{ + spiffs_DIR dir; + if (!SPIFFS_opendir (&fs, "/", &dir)) + die ("spiffs_opendir"); + struct spiffs_dirent de; + while (SPIFFS_readdir (&dir, &de)) + { + static const char types[] = "?fdhs"; // file, dir, hardlink, softlink + char name[sizeof(de.name)+1] = { 0 }; + memcpy (name, de.name, sizeof(de.name)); + printf("%c %6u %s\n", types[de.type], de.size, name); + } + SPIFFS_closedir (&dir); +} + + +static void cat (char *fname) +{ + spiffs_file fh = SPIFFS_open (&fs, fname, SPIFFS_RDONLY, 0); + char buff[512]; + s32_t n; + while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0) + write (STDOUT_FILENO, buff, n); + SPIFFS_close (&fs, fh); +} + + +static void import (char *src, char *dst) +{ + int fd = open (src, O_RDONLY); + if (fd < 0) + die (src); + + spiffs_file fh = SPIFFS_open (&fs, dst, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + if (fh < 0) + die ("spiffs_open"); + + char buff[16384]; + s32_t n; + while ((n = read (fd, buff, sizeof (buff))) > 0) + if (SPIFFS_write (&fs, fh, buff, n) < 0) + die ("spiffs_write"); + + if (SPIFFS_close (&fs, fh) < 0) + die("spiffs_close"); + close (fd); +} + + +static void export (char *src, char *dst) +{ + spiffs_file fh = SPIFFS_open (&fs, src, SPIFFS_RDONLY, 0); + if (fh < 0) + die ("spiffs_open"); + + int fd = open (dst, O_CREAT | O_TRUNC | O_WRONLY, 0664); + if (fd < 0) + die (dst); + + char buff[512]; + s32_t n; + while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0) + if (write (fd, buff, n) < 0) + die ("write"); + + SPIFFS_close (&fs, fh); + close (fd); +} + + +char *trim (char *in) +{ + if (!in) + return ""; + + char *out = 0; + while (*in) + { + if (!out && !isspace (*in)) + out = in; + ++in; + } + if (!out) + return ""; + while (--in > out && isspace (*in)) + ; + in[1] = 0; + return out; +} + + +void syntax (void) +{ + fprintf (stderr, + "Syntax: spiffsimg -f [-d] [-o ] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r ]\n\n" + ); + exit (1); +} + +static size_t getsize(const char *s) +{ + char *end = 0; + size_t val = strtoul(s, &end, 0); + + if (end) { + int factor; + if (*end == 'k' || *end == 'K') { + factor = 1 << 10; + end++; + } else if (*end == 'm' || *end == 'M') { + factor = 1 << 20; + end++; + } else { + factor = 1; + } + // Capital B is bytes + if (*end == 'B') { + factor = factor << 3; + } + // we want bytes + val = (val * factor) / 8; + } + + return val; +} + +int main (int argc, char *argv[]) +{ + if (argc == 1) + syntax (); + + int opt; + const char *fname = 0; + bool create = false; + enum { CMD_NONE, CMD_LIST, CMD_INTERACTIVE, CMD_SCRIPT } command = CMD_NONE; + int sz = 0; + const char *script_name = 0; + const char *resolved = 0; + int flashsize = 0; + int used = 0; + while ((opt = getopt (argc, argv, "do:f:c:lir:S:U:")) != -1) + { + switch (opt) + { + case 'f': fname = optarg; break; + case 'o': resolved = optarg; break; + case 'c': create = true; sz = strtol(optarg, 0, 0); break; + case 'S': create = true; flashsize = getsize(optarg); break; + case 'U': create = true; used = strtol(optarg, 0, 0); break; + case 'd': delete_on_die = 1; break; + case 'l': command = CMD_LIST; break; + case 'i': command = CMD_INTERACTIVE; break; + case 'r': command = CMD_SCRIPT; script_name = optarg; break; + default: die ("unknown option"); + } + } + + if (!fname) { + die("Need a filename"); + } + +#ifdef _MSC_VER + _set_fmode( _O_BINARY ); //change default open mode to binary rather than text +#endif + int fd; + + if (create) + { + if (!sz) { + if (!flashsize || !used) { + die("Missing flashSize or Used"); + } + sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096; // This leaves space for the parameter area + if (sz < 0x4000) { + die("Not enough space"); + } + if (sz > SMALL_FILESYSTEM) { + used = (used + 0xffff) & ~0xffff; + } else { + used = (used + 0x1fff) & ~0x1fff; + } + sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096; + } + sz &= ~(0x1fff); + + if (used == 0) { + if (strchr(fname, '%')) { + die("Unable to calculate where to put the flash image, and % present in filename"); + } + } + + char fnamebuff[1024]; + + sprintf(fnamebuff, fname, used); + + delete_list[delete_list_index++] = strdup(fnamebuff);; + fd = open (fnamebuff, (create ? (O_CREAT | O_TRUNC) : 0) | O_RDWR, 0664); + if (fd == -1) + die ("open"); + + if (resolved) { + delete_list[delete_list_index++] = resolved; + FILE *f = fopen(resolved, "w"); + fprintf(f, "0x%x", used); + fclose(f); + } + + if (lseek (fd, sz -1, SEEK_SET) == -1) + die ("lseek"); + if (write (fd, "", 1) != 1) + die ("write"); + } + else { + fd = open (fname, O_RDWR, 0664); + if (fd == -1) + die ("open"); + + if (!sz) + { + off_t offs = lseek (fd, 0, SEEK_END); + if (offs == -1) + die ("lseek"); + sz = offs; + } + } + + if (sz & (0x1000 -1)) + die ("file size not multiple of erase block size"); + +#ifdef _MSC_VER + //We don't have a mmap(), so we simply allocate a file buffer we write out + //at the end of the program. This also means that we need to let the program + //end normally (i.e. not via Ctrl-C) or else that final write will not happen. + //If you are in interactive mode, there is not a command for 'exit', however + //EOF may be used to end the interactive loop by pressing Ctrl-Z, return. + flash = (uint8_t*)malloc( sz ); + if ( lseek( fd, 0, SEEK_SET ) == -1 ) + die( "lseek" ); + if ( read( fd, flash, sz ) != sz ) + die( "write" ); +#else + flash = mmap( 0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); +#endif + if (!flash) + die ("mmap"); + + if (create) + memset (flash, 0xff, sz); + + spiffs_config cfg; + cfg.phys_size = sz; + cfg.phys_addr = 0; + cfg.phys_erase_block = 0x1000; + cfg.log_block_size = 0x1000 * (sz > SMALL_FILESYSTEM ? 2 : 1); + cfg.log_page_size = LOG_PAGE_SIZE; + cfg.hal_read_f = flash_read; + cfg.hal_write_f = flash_write; + cfg.hal_erase_f = flash_erase; + if (cfg.phys_size < 4 * cfg.log_block_size) { + die("disk not large enough for four blocks"); + } + + if (SPIFFS_mount (&fs, &cfg, + spiffs_work_buf, + spiffs_fds, + sizeof(spiffs_fds), + malloc(65536), 65536, 0) != 0) { + if (create) { + if (SPIFFS_format(&fs) != 0) { + die("spiffs_format"); + } + if (SPIFFS_mount (&fs, &cfg, + spiffs_work_buf, + spiffs_fds, + sizeof(spiffs_fds), + malloc(65536), 65536, 0) != 0) { + die ("spiffs_mount"); + } + if (command == CMD_INTERACTIVE) { + printf("Created filesystem -- size 0x%x, block_size=%d\n", cfg.phys_size, cfg.log_block_size); + } + } else { + die ("spiffs_mount"); + } + } + + if (command == CMD_NONE) + ; // maybe just wanted to create an empty image? + else if (command == CMD_LIST) + list (); + else + { + FILE *in = (command == CMD_INTERACTIVE) ? stdin : fopen (script_name, "r"); + if (!in) + die ("fopen"); + char buff[128] = { 0 }; + if (in == stdin) + printf("> "); + while (fgets (buff, sizeof (buff) -1, in)) + { + char *line = trim (buff); + if (!line[0] || line[0] == '#') + continue; + if (strcmp (line, "ls") == 0) + list (); + else if (strncmp (line, "import ", 7) == 0) + { + char *src = 0, *dst = 0; +#ifdef _MSC_VER + src = (char*)malloc(260 + 1); //MAX_PATH + dst = (char*)malloc( 260 + 1 ); + if (sscanf (line +7, " %260s %260s", src, dst) != 2) +#else + if (sscanf (line +7, " %ms %ms", &src, &dst) != 2) +#endif + { + fprintf (stderr, "SYNTAX ERROR: %s\n", line); + retcode = 1; + } + else + import (src, dst); + free (src); + free (dst); + } + else if (strncmp (line, "export ", 7) == 0) + { + char *src = 0, *dst = 0; +#ifdef _MSC_VER + src = (char*)malloc( 260 + 1 ); //MAX_PATH + dst = (char*)malloc( 260 + 1 ); + if ( sscanf( line + 7, " %260s %260s", src, dst ) != 2 ) +#else + if (sscanf (line + 7, " %ms %ms", &src, &dst) != 2) +#endif + { + fprintf (stderr, "SYNTAX ERROR: %s\n", line); + retcode = 1; + } + else + export (src, dst); + free (src); + free (dst); + } + else if (strncmp (line, "rm ", 3) == 0) + { + if (SPIFFS_remove (&fs, trim (line + 3)) < 0) + { + fprintf (stderr, "FAILED: %s\n", line); + retcode = 1; + } + } + else if (strncmp (line, "cat ", 4) == 0) + cat (trim (line + 4)); + else if (strncmp (line, "info", 4) == 0) + { + u32_t total, used; + if (SPIFFS_info (&fs, &total, &used) < 0) + { + fprintf (stderr, "FAILED: %s\n", line); + retcode = 1; + } + else + printf ("Total: %u, Used: %u\n", total, used); + } + else + { + printf ("SYNTAX ERROR: %s\n", line); + retcode = 1; + } + + if (in == stdin) + printf ("> "); + } + if (in == stdin) + printf ("\n"); + } + + SPIFFS_unmount (&fs); +#ifdef _MSC_VER + if ( lseek( fd, 0, SEEK_SET ) == -1 ) + die( "lseek" ); + if ( write( fd, flash, sz ) != sz ) + die( "write" ); + free( flash ); +#else + munmap (flash, sz); +#endif + close (fd); + return retcode; +} diff --git a/tools/spiffsimg/spiffs_typedefs.h b/tools/spiffsimg/spiffs_typedefs.h index f694d125..c0dd2591 100644 --- a/tools/spiffsimg/spiffs_typedefs.h +++ b/tools/spiffsimg/spiffs_typedefs.h @@ -10,7 +10,7 @@ typedef uint16_t u16_t; typedef int8_t s8_t; typedef uint8_t u8_t; -#ifndef __CYGWIN__ +#if !defined(__CYGWIN__) && !defined(_MSC_VER) typedef long long ptrdiff_t; #define offsetof(type, member) __builtin_offsetof (type, member) #endif