main.c 11 KB

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