main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /*
  2. * Copyright 2015 Dius Computing Pty Ltd. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * - Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * - Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the
  13. * distribution.
  14. * - Neither the name of the copyright holders nor the names of
  15. * its contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  22. * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  23. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  25. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  27. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  29. * OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * @author Johny Mattsson <jmattsson@dius.com.au>
  32. */
  33. #include <stdint.h>
  34. #include <stdbool.h>
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #ifdef _MSC_VER
  39. #include "getopt.h" /* local copy from MingW project */
  40. #include <io.h>
  41. #define STDIN_FILENO 0
  42. #define STDOUT_FILENO 1
  43. #define STDERR_FILENO 2
  44. typedef ptrdiff_t off_t;
  45. #else
  46. #include <unistd.h>
  47. #include <getopt.h>
  48. #include <sys/mman.h>
  49. #endif
  50. #include <fcntl.h>
  51. #include <errno.h>
  52. #include "spiffs.h"
  53. #define NO_CPU_ESP8266_INCLUDE
  54. #include "../platform/cpu_esp8266.h"
  55. static spiffs fs;
  56. static uint8_t *flash;
  57. static int retcode = 0;
  58. #define LOG_PAGE_SIZE 256
  59. // If the caclulated size is this or less, then use smaller blocks
  60. // (1 page) rather than the normal 2 pages. This gives a little bit
  61. // more flexibility for the file system, at the expense of a bit of
  62. // efficiency
  63. #define SMALL_FILESYSTEM (128 * 1024)
  64. static int delete_on_die = 0;
  65. static const char *delete_list[10];
  66. static int delete_list_index = 0;
  67. static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
  68. static u8_t spiffs_fds[32*4];
  69. static s32_t flash_read (u32_t addr, u32_t size, u8_t *dst) {
  70. memcpy (dst, flash + addr, size);
  71. return SPIFFS_OK;
  72. }
  73. static s32_t flash_write (u32_t addr, u32_t size, u8_t *src) {
  74. memcpy (flash + addr, src, size);
  75. return SPIFFS_OK;
  76. }
  77. static s32_t flash_erase (u32_t addr, u32_t size) {
  78. memset (flash + addr, 0xff, size);
  79. return SPIFFS_OK;
  80. }
  81. static void die (const char *what)
  82. {
  83. if (errno == 0) {
  84. fprintf(stderr, "%s: fatal error\n", what);
  85. } else {
  86. perror (what);
  87. }
  88. if (delete_on_die) {
  89. const char **p = delete_list;
  90. while (*p) {
  91. unlink(*p);
  92. p++;
  93. }
  94. }
  95. exit (1);
  96. }
  97. static void list (void)
  98. {
  99. spiffs_DIR dir;
  100. if (!SPIFFS_opendir (&fs, "/", &dir))
  101. die ("spiffs_opendir");
  102. struct spiffs_dirent de;
  103. while (SPIFFS_readdir (&dir, &de))
  104. {
  105. static const char types[] = "?fdhs"; // file, dir, hardlink, softlink
  106. char name[sizeof(de.name)+1] = { 0 };
  107. memcpy (name, de.name, sizeof(de.name));
  108. printf("%c %6u %s\n", types[de.type], de.size, name);
  109. }
  110. SPIFFS_closedir (&dir);
  111. }
  112. static void cat (char *fname)
  113. {
  114. spiffs_file fh = SPIFFS_open (&fs, fname, SPIFFS_RDONLY, 0);
  115. char buff[512];
  116. s32_t n;
  117. while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
  118. write (STDOUT_FILENO, buff, n);
  119. SPIFFS_close (&fs, fh);
  120. }
  121. static void import (char *src, char *dst)
  122. {
  123. int fd = open (src, O_RDONLY);
  124. if (fd < 0)
  125. die (src);
  126. spiffs_file fh = SPIFFS_open (&fs, dst, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0);
  127. if (fh < 0)
  128. die ("spiffs_open");
  129. char buff[16384];
  130. s32_t n;
  131. while ((n = read (fd, buff, sizeof (buff))) > 0)
  132. if (SPIFFS_write (&fs, fh, buff, n) < 0)
  133. die ("spiffs_write");
  134. if (SPIFFS_close (&fs, fh) < 0)
  135. die("spiffs_close");
  136. close (fd);
  137. }
  138. static void export (char *src, char *dst)
  139. {
  140. spiffs_file fh = SPIFFS_open (&fs, src, SPIFFS_RDONLY, 0);
  141. if (fh < 0)
  142. die ("spiffs_open");
  143. int fd = open (dst, O_CREAT | O_TRUNC | O_WRONLY, 0664);
  144. if (fd < 0)
  145. die (dst);
  146. char buff[512];
  147. s32_t n;
  148. while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
  149. if (write (fd, buff, n) < 0)
  150. die ("write");
  151. SPIFFS_close (&fs, fh);
  152. close (fd);
  153. }
  154. char *trim (char *in)
  155. {
  156. if (!in)
  157. return "";
  158. char *out = 0;
  159. while (*in)
  160. {
  161. if (!out && !isspace (*in))
  162. out = in;
  163. ++in;
  164. }
  165. if (!out)
  166. return "";
  167. while (--in > out && isspace (*in))
  168. ;
  169. in[1] = 0;
  170. return out;
  171. }
  172. void syntax (void)
  173. {
  174. fprintf (stderr,
  175. "Syntax: spiffsimg -f <filename> [-d] [-o <locationfilename>] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r <scriptname> ]\n\n"
  176. );
  177. exit (1);
  178. }
  179. static size_t getsize(const char *s)
  180. {
  181. char *end = 0;
  182. size_t val = strtoul(s, &end, 0);
  183. if (end) {
  184. int factor;
  185. if (*end == 'k' || *end == 'K') {
  186. factor = 1 << 10;
  187. end++;
  188. } else if (*end == 'm' || *end == 'M') {
  189. factor = 1 << 20;
  190. end++;
  191. } else {
  192. factor = 1;
  193. }
  194. // Capital B is bytes
  195. if (*end == 'B') {
  196. factor = factor << 3;
  197. }
  198. // we want bytes
  199. val = (val * factor) / 8;
  200. }
  201. return val;
  202. }
  203. int main (int argc, char *argv[])
  204. {
  205. if (argc == 1)
  206. syntax ();
  207. int opt;
  208. const char *fname = 0;
  209. bool create = false;
  210. enum { CMD_NONE, CMD_LIST, CMD_INTERACTIVE, CMD_SCRIPT } command = CMD_NONE;
  211. int sz = 0;
  212. const char *script_name = 0;
  213. const char *resolved = 0;
  214. int flashsize = 0;
  215. int used = 0;
  216. while ((opt = getopt (argc, argv, "do:f:c:lir:S:U:")) != -1)
  217. {
  218. switch (opt)
  219. {
  220. case 'f': fname = optarg; break;
  221. case 'o': resolved = optarg; break;
  222. case 'c': create = true; sz = strtol(optarg, 0, 0); break;
  223. case 'S': create = true; flashsize = getsize(optarg); break;
  224. case 'U': create = true; used = strtol(optarg, 0, 0); break;
  225. case 'd': delete_on_die = 1; break;
  226. case 'l': command = CMD_LIST; break;
  227. case 'i': command = CMD_INTERACTIVE; break;
  228. case 'r': command = CMD_SCRIPT; script_name = optarg; break;
  229. default: die ("unknown option");
  230. }
  231. }
  232. if (!fname) {
  233. die("Need a filename");
  234. }
  235. #ifdef _MSC_VER
  236. _set_fmode( _O_BINARY ); //change default open mode to binary rather than text
  237. #endif
  238. int fd;
  239. if (create)
  240. {
  241. if (!sz) {
  242. if (!flashsize || !used) {
  243. die("Missing flashSize or Used");
  244. }
  245. sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096; // This leaves space for the parameter area
  246. if (sz < 0x4000) {
  247. die("Not enough space");
  248. }
  249. if (sz > SMALL_FILESYSTEM) {
  250. used = (used + 0xffff) & ~0xffff;
  251. } else {
  252. used = (used + 0x1fff) & ~0x1fff;
  253. }
  254. sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096;
  255. }
  256. sz &= ~(0x1fff);
  257. if (used == 0) {
  258. if (strchr(fname, '%')) {
  259. die("Unable to calculate where to put the flash image, and % present in filename");
  260. }
  261. }
  262. char fnamebuff[1024];
  263. sprintf(fnamebuff, fname, used);
  264. delete_list[delete_list_index++] = strdup(fnamebuff);;
  265. fd = open (fnamebuff, (create ? (O_CREAT | O_TRUNC) : 0) | O_RDWR, 0664);
  266. if (fd == -1)
  267. die ("open");
  268. if (resolved) {
  269. delete_list[delete_list_index++] = resolved;
  270. FILE *f = fopen(resolved, "w");
  271. fprintf(f, "0x%x", used);
  272. fclose(f);
  273. }
  274. if (lseek (fd, sz -1, SEEK_SET) == -1)
  275. die ("lseek");
  276. if (write (fd, "", 1) != 1)
  277. die ("write");
  278. }
  279. else {
  280. fd = open (fname, O_RDWR, 0664);
  281. if (fd == -1)
  282. die ("open");
  283. if (!sz)
  284. {
  285. off_t offs = lseek (fd, 0, SEEK_END);
  286. if (offs == -1)
  287. die ("lseek");
  288. sz = offs;
  289. }
  290. }
  291. if (sz & (0x1000 -1))
  292. die ("file size not multiple of erase block size");
  293. #ifdef _MSC_VER
  294. //We don't have a mmap(), so we simply allocate a file buffer we write out
  295. //at the end of the program. This also means that we need to let the program
  296. //end normally (i.e. not via Ctrl-C) or else that final write will not happen.
  297. //If you are in interactive mode, there is not a command for 'exit', however
  298. //EOF may be used to end the interactive loop by pressing Ctrl-Z, return.
  299. flash = (uint8_t*)malloc( sz );
  300. if ( lseek( fd, 0, SEEK_SET ) == -1 )
  301. die( "lseek" );
  302. if ( read( fd, flash, sz ) != sz )
  303. die( "write" );
  304. #else
  305. flash = mmap( 0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
  306. #endif
  307. if (!flash)
  308. die ("mmap");
  309. if (create)
  310. memset (flash, 0xff, sz);
  311. spiffs_config cfg;
  312. cfg.phys_size = sz;
  313. cfg.phys_addr = 0;
  314. cfg.phys_erase_block = 0x1000;
  315. cfg.log_block_size = 0x1000 * (sz > SMALL_FILESYSTEM ? 2 : 1);
  316. cfg.log_page_size = LOG_PAGE_SIZE;
  317. cfg.hal_read_f = flash_read;
  318. cfg.hal_write_f = flash_write;
  319. cfg.hal_erase_f = flash_erase;
  320. if (cfg.phys_size < 4 * cfg.log_block_size) {
  321. die("disk not large enough for four blocks");
  322. }
  323. if (SPIFFS_mount (&fs, &cfg,
  324. spiffs_work_buf,
  325. spiffs_fds,
  326. sizeof(spiffs_fds),
  327. malloc(65536), 65536, 0) != 0) {
  328. if (create) {
  329. if (SPIFFS_format(&fs) != 0) {
  330. die("spiffs_format");
  331. }
  332. if (SPIFFS_mount (&fs, &cfg,
  333. spiffs_work_buf,
  334. spiffs_fds,
  335. sizeof(spiffs_fds),
  336. malloc(65536), 65536, 0) != 0) {
  337. die ("spiffs_mount");
  338. }
  339. if (command == CMD_INTERACTIVE) {
  340. printf("Created filesystem -- size 0x%x, block_size=%d\n", cfg.phys_size, cfg.log_block_size);
  341. }
  342. } else {
  343. die ("spiffs_mount");
  344. }
  345. }
  346. if (command == CMD_NONE)
  347. ; // maybe just wanted to create an empty image?
  348. else if (command == CMD_LIST)
  349. list ();
  350. else
  351. {
  352. FILE *in = (command == CMD_INTERACTIVE) ? stdin : fopen (script_name, "r");
  353. if (!in)
  354. die ("fopen");
  355. char buff[128] = { 0 };
  356. if (in == stdin)
  357. printf("> ");
  358. while (fgets (buff, sizeof (buff) -1, in))
  359. {
  360. char *line = trim (buff);
  361. if (!line[0] || line[0] == '#')
  362. continue;
  363. if (strcmp (line, "ls") == 0)
  364. list ();
  365. else if (strncmp (line, "import ", 7) == 0)
  366. {
  367. char *src = 0, *dst = 0;
  368. #ifdef _MSC_VER
  369. src = (char*)malloc(260 + 1); //MAX_PATH
  370. dst = (char*)malloc( 260 + 1 );
  371. if (sscanf (line +7, " %260s %260s", src, dst) != 2)
  372. #else
  373. if (sscanf (line +7, " %ms %ms", &src, &dst) != 2)
  374. #endif
  375. {
  376. fprintf (stderr, "SYNTAX ERROR: %s\n", line);
  377. retcode = 1;
  378. }
  379. else
  380. import (src, dst);
  381. free (src);
  382. free (dst);
  383. }
  384. else if (strncmp (line, "export ", 7) == 0)
  385. {
  386. char *src = 0, *dst = 0;
  387. #ifdef _MSC_VER
  388. src = (char*)malloc( 260 + 1 ); //MAX_PATH
  389. dst = (char*)malloc( 260 + 1 );
  390. if ( sscanf( line + 7, " %260s %260s", src, dst ) != 2 )
  391. #else
  392. if (sscanf (line + 7, " %ms %ms", &src, &dst) != 2)
  393. #endif
  394. {
  395. fprintf (stderr, "SYNTAX ERROR: %s\n", line);
  396. retcode = 1;
  397. }
  398. else
  399. export (src, dst);
  400. free (src);
  401. free (dst);
  402. }
  403. else if (strncmp (line, "rm ", 3) == 0)
  404. {
  405. if (SPIFFS_remove (&fs, trim (line + 3)) < 0)
  406. {
  407. fprintf (stderr, "FAILED: %s\n", line);
  408. retcode = 1;
  409. }
  410. }
  411. else if (strncmp (line, "cat ", 4) == 0)
  412. cat (trim (line + 4));
  413. else if (strncmp (line, "info", 4) == 0)
  414. {
  415. u32_t total, used;
  416. if (SPIFFS_info (&fs, &total, &used) < 0)
  417. {
  418. fprintf (stderr, "FAILED: %s\n", line);
  419. retcode = 1;
  420. }
  421. else
  422. printf ("Total: %u, Used: %u\n", total, used);
  423. }
  424. else
  425. {
  426. printf ("SYNTAX ERROR: %s\n", line);
  427. retcode = 1;
  428. }
  429. if (in == stdin)
  430. printf ("> ");
  431. }
  432. if (in == stdin)
  433. printf ("\n");
  434. }
  435. SPIFFS_unmount (&fs);
  436. #ifdef _MSC_VER
  437. if ( lseek( fd, 0, SEEK_SET ) == -1 )
  438. die( "lseek" );
  439. if ( write( fd, flash, sz ) != sz )
  440. die( "write" );
  441. free( flash );
  442. #else
  443. munmap (flash, sz);
  444. #endif
  445. close (fd);
  446. return retcode;
  447. }