main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. #include <unistd.h>
  39. #include <fcntl.h>
  40. #include <getopt.h>
  41. #include <sys/mman.h>
  42. #include <errno.h>
  43. #include "spiffs.h"
  44. #define NO_CPU_ESP8266_INCLUDE
  45. #include "../platform/cpu_esp8266.h"
  46. static spiffs fs;
  47. static uint8_t *flash;
  48. static int retcode = 0;
  49. #define LOG_PAGE_SIZE 256
  50. // If the caclulated size is this or less, then use smaller blocks
  51. // (1 page) rather than the normal 2 pages. This gives a little bit
  52. // more flexibility for the file system, at the expense of a bit of
  53. // efficiency
  54. #define SMALL_FILESYSTEM (128 * 1024)
  55. static int delete_on_die = 0;
  56. static const char *delete_list[10];
  57. static int delete_list_index = 0;
  58. static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
  59. static u8_t spiffs_fds[32*4];
  60. static s32_t flash_read (u32_t addr, u32_t size, u8_t *dst) {
  61. memcpy (dst, flash + addr, size);
  62. return SPIFFS_OK;
  63. }
  64. static s32_t flash_write (u32_t addr, u32_t size, u8_t *src) {
  65. memcpy (flash + addr, src, size);
  66. return SPIFFS_OK;
  67. }
  68. static s32_t flash_erase (u32_t addr, u32_t size) {
  69. memset (flash + addr, 0xff, size);
  70. return SPIFFS_OK;
  71. }
  72. static void die (const char *what)
  73. {
  74. if (errno == 0) {
  75. fprintf(stderr, "%s: fatal error\n", what);
  76. } else {
  77. perror (what);
  78. }
  79. if (delete_on_die) {
  80. const char **p = delete_list;
  81. while (*p) {
  82. unlink(*p);
  83. p++;
  84. }
  85. }
  86. exit (1);
  87. }
  88. static void list (void)
  89. {
  90. spiffs_DIR dir;
  91. if (!SPIFFS_opendir (&fs, "/", &dir))
  92. die ("spiffs_opendir");
  93. struct spiffs_dirent de;
  94. while (SPIFFS_readdir (&dir, &de))
  95. {
  96. static const char types[] = "?fdhs"; // file, dir, hardlink, softlink
  97. char name[sizeof(de.name)+1] = { 0 };
  98. memcpy (name, de.name, sizeof(de.name));
  99. printf("%c %6u %s\n", types[de.type], de.size, name);
  100. }
  101. SPIFFS_closedir (&dir);
  102. }
  103. static void cat (char *fname)
  104. {
  105. spiffs_file fh = SPIFFS_open (&fs, fname, SPIFFS_RDONLY, 0);
  106. char buff[512];
  107. s32_t n;
  108. while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
  109. write (STDOUT_FILENO, buff, n);
  110. SPIFFS_close (&fs, fh);
  111. }
  112. static void import (char *src, char *dst)
  113. {
  114. int fd = open (src, O_RDONLY);
  115. if (fd < 0)
  116. die (src);
  117. spiffs_file fh = SPIFFS_open (&fs, dst, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0);
  118. if (fh < 0)
  119. die ("spiffs_open");
  120. char buff[16384];
  121. s32_t n;
  122. while ((n = read (fd, buff, sizeof (buff))) > 0)
  123. if (SPIFFS_write (&fs, fh, buff, n) < 0)
  124. die ("spiffs_write");
  125. if (SPIFFS_close (&fs, fh) < 0)
  126. die("spiffs_close");
  127. close (fd);
  128. }
  129. static void export (char *src, char *dst)
  130. {
  131. spiffs_file fh = SPIFFS_open (&fs, src, SPIFFS_RDONLY, 0);
  132. if (fh < 0)
  133. die ("spiffs_open");
  134. int fd = open (dst, O_CREAT | O_TRUNC | O_WRONLY, 0664);
  135. if (fd < 0)
  136. die (dst);
  137. char buff[512];
  138. s32_t n;
  139. while ((n = SPIFFS_read (&fs, fh, buff, sizeof (buff))) > 0)
  140. if (write (fd, buff, n) < 0)
  141. die ("write");
  142. SPIFFS_close (&fs, fh);
  143. close (fd);
  144. }
  145. char *trim (char *in)
  146. {
  147. if (!in)
  148. return "";
  149. char *out = 0;
  150. while (*in)
  151. {
  152. if (!out && !isspace (*in))
  153. out = in;
  154. ++in;
  155. }
  156. if (!out)
  157. return "";
  158. while (--in > out && isspace (*in))
  159. ;
  160. in[1] = 0;
  161. return out;
  162. }
  163. void syntax (void)
  164. {
  165. fprintf (stderr,
  166. "Syntax: spiffsimg -f <filename> [-d] [-o <locationfilename>] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r <scriptname> ]\n\n"
  167. );
  168. exit (1);
  169. }
  170. static size_t getsize(const char *s)
  171. {
  172. char *end = 0;
  173. size_t val = strtoul(s, &end, 0);
  174. if (end) {
  175. int factor;
  176. if (*end == 'k' || *end == 'K') {
  177. factor = 1 << 10;
  178. end++;
  179. } else if (*end == 'm' || *end == 'M') {
  180. factor = 1 << 20;
  181. end++;
  182. } else {
  183. factor = 1;
  184. }
  185. // Capital B is bytes
  186. if (*end == 'B') {
  187. factor = factor << 3;
  188. }
  189. // we want bytes
  190. val = (val * factor) / 8;
  191. }
  192. return val;
  193. }
  194. int main (int argc, char *argv[])
  195. {
  196. if (argc == 1)
  197. syntax ();
  198. int opt;
  199. const char *fname = 0;
  200. bool create = false;
  201. enum { CMD_NONE, CMD_LIST, CMD_INTERACTIVE, CMD_SCRIPT } command = CMD_NONE;
  202. int sz = 0;
  203. const char *script_name = 0;
  204. const char *resolved = 0;
  205. int flashsize = 0;
  206. int used = 0;
  207. while ((opt = getopt (argc, argv, "do:f:c:lir:S:U:")) != -1)
  208. {
  209. switch (opt)
  210. {
  211. case 'f': fname = optarg; break;
  212. case 'o': resolved = optarg; break;
  213. case 'c': create = true; sz = strtol(optarg, 0, 0); break;
  214. case 'S': create = true; flashsize = getsize(optarg); break;
  215. case 'U': create = true; used = strtol(optarg, 0, 0); break;
  216. case 'd': delete_on_die = 1; break;
  217. case 'l': command = CMD_LIST; break;
  218. case 'i': command = CMD_INTERACTIVE; break;
  219. case 'r': command = CMD_SCRIPT; script_name = optarg; break;
  220. default: die ("unknown option");
  221. }
  222. }
  223. if (!fname) {
  224. die("Need a filename");
  225. }
  226. int fd;
  227. if (create)
  228. {
  229. if (!sz) {
  230. if (!flashsize || !used) {
  231. die("Missing flashSize or Used");
  232. }
  233. sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096; // This leaves space for the parameter area
  234. if (sz < 0x4000) {
  235. die("Not enough space");
  236. }
  237. if (sz > SMALL_FILESYSTEM) {
  238. used = (used + 0xffff) & ~0xffff;
  239. } else {
  240. used = (used + 0x1fff) & ~0x1fff;
  241. }
  242. sz = flashsize - used - SYS_PARAM_SEC_NUM * 4096;
  243. }
  244. sz &= ~(0x1fff);
  245. char fnamebuff[1024];
  246. sprintf(fnamebuff, fname, used);
  247. delete_list[delete_list_index++] = strdup(fnamebuff);;
  248. fd = open (fnamebuff, (create ? (O_CREAT | O_TRUNC) : 0) | O_RDWR, 0664);
  249. if (fd == -1)
  250. die ("open");
  251. if (resolved) {
  252. delete_list[delete_list_index++] = resolved;
  253. FILE *f = fopen(resolved, "w");
  254. fprintf(f, "0x%x", used);
  255. fclose(f);
  256. }
  257. if (lseek (fd, sz -1, SEEK_SET) == -1)
  258. die ("lseek");
  259. if (write (fd, "", 1) != 1)
  260. die ("write");
  261. }
  262. else {
  263. fd = open (fname, O_RDWR, 0664);
  264. if (fd == -1)
  265. die ("open");
  266. if (!sz)
  267. {
  268. off_t offs = lseek (fd, 0, SEEK_END);
  269. if (offs == -1)
  270. die ("lseek");
  271. sz = offs;
  272. }
  273. }
  274. if (sz & (0x1000 -1))
  275. die ("file size not multiple of erase block size");
  276. flash = mmap (0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  277. if (!flash)
  278. die ("mmap");
  279. if (create)
  280. memset (flash, 0xff, sz);
  281. spiffs_config cfg;
  282. cfg.phys_size = sz;
  283. cfg.phys_addr = 0;
  284. cfg.phys_erase_block = 0x1000;
  285. cfg.log_block_size = 0x1000 * (sz > SMALL_FILESYSTEM ? 2 : 1);
  286. cfg.log_page_size = LOG_PAGE_SIZE;
  287. cfg.hal_read_f = flash_read;
  288. cfg.hal_write_f = flash_write;
  289. cfg.hal_erase_f = flash_erase;
  290. if (cfg.phys_size < 4 * cfg.log_block_size) {
  291. die("disk not large enough for four blocks");
  292. }
  293. if (SPIFFS_mount (&fs, &cfg,
  294. spiffs_work_buf,
  295. spiffs_fds,
  296. sizeof(spiffs_fds),
  297. malloc(65536), 65536, 0) != 0) {
  298. if (create) {
  299. if (SPIFFS_format(&fs) != 0) {
  300. die("spiffs_format");
  301. }
  302. if (SPIFFS_mount (&fs, &cfg,
  303. spiffs_work_buf,
  304. spiffs_fds,
  305. sizeof(spiffs_fds),
  306. malloc(65536), 65536, 0) != 0) {
  307. die ("spiffs_mount");
  308. }
  309. if (command == CMD_INTERACTIVE) {
  310. printf("Created filesystem -- size 0x%x, block_size=%d\n", cfg.phys_size, cfg.log_block_size);
  311. }
  312. } else {
  313. die ("spiffs_mount");
  314. }
  315. }
  316. if (command == CMD_NONE)
  317. ; // maybe just wanted to create an empty image?
  318. else if (command == CMD_LIST)
  319. list ();
  320. else
  321. {
  322. FILE *in = (command == CMD_INTERACTIVE) ? stdin : fopen (script_name, "r");
  323. if (!in)
  324. die ("fopen");
  325. char buff[128] = { 0 };
  326. if (in == stdin)
  327. printf("> ");
  328. while (fgets (buff, sizeof (buff) -1, in))
  329. {
  330. char *line = trim (buff);
  331. if (!line[0] || line[0] == '#')
  332. continue;
  333. if (strcmp (line, "ls") == 0)
  334. list ();
  335. else if (strncmp (line, "import ", 7) == 0)
  336. {
  337. char *src = 0, *dst = 0;
  338. if (sscanf (line +7, " %ms %ms", &src, &dst) != 2)
  339. {
  340. fprintf (stderr, "SYNTAX ERROR: %s\n", line);
  341. retcode = 1;
  342. }
  343. else
  344. import (src, dst);
  345. free (src);
  346. free (dst);
  347. }
  348. else if (strncmp (line, "export ", 7) == 0)
  349. {
  350. char *src = 0, *dst = 0;
  351. if (sscanf (line + 7, " %ms %ms", &src, &dst) != 2)
  352. {
  353. fprintf (stderr, "SYNTAX ERROR: %s\n", line);
  354. retcode = 1;
  355. }
  356. else
  357. export (src, dst);
  358. free (src);
  359. free (dst);
  360. }
  361. else if (strncmp (line, "rm ", 3) == 0)
  362. {
  363. if (SPIFFS_remove (&fs, trim (line + 3)) < 0)
  364. {
  365. fprintf (stderr, "FAILED: %s\n", line);
  366. retcode = 1;
  367. }
  368. }
  369. else if (strncmp (line, "cat ", 4) == 0)
  370. cat (trim (line + 4));
  371. else if (strncmp (line, "info", 4) == 0)
  372. {
  373. u32_t total, used;
  374. if (SPIFFS_info (&fs, &total, &used) < 0)
  375. {
  376. fprintf (stderr, "FAILED: %s\n", line);
  377. retcode = 1;
  378. }
  379. else
  380. printf ("Total: %u, Used: %u\n", total, used);
  381. }
  382. else
  383. {
  384. printf ("SYNTAX ERROR: %s\n", line);
  385. retcode = 1;
  386. }
  387. if (in == stdin)
  388. printf ("> ");
  389. }
  390. if (in == stdin)
  391. printf ("\n");
  392. }
  393. SPIFFS_unmount (&fs);
  394. munmap (flash, sz);
  395. close (fd);
  396. return retcode;
  397. }