123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- /*
- * 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 <jmattsson@dius.com.au>
- */
- #include <stdint.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <sys/mman.h>
- #include <errno.h>
- #include "spiffs.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 <filename> [-d] [-o <locationfilename>] [-c size] [-S flashsize] [-U usedsize] [-l | -i | -r <scriptname> ]\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 - 4 * 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 - 4 * 4096;
- }
- sz &= ~(0x1fff);
- 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;
- }
|