@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <byteswap.h>
#include <getopt.h>
+#include <time.h>
#include <calculatecrc.h>
#include <crclib.h>
@@ -59,6 +60,11 @@ struct sloffs {
char *name;
};
+/* sloffs metadata size:
+ * 4 * 8: 4 * uint64_t + (filename length) */
+#define SLOFFS_META (4 * 8)
+#define ALIGN64(x) (((x) + 7) & ~7)
+
static struct sloffs *
next_file(struct sloffs *sloffs)
{
@@ -82,6 +88,185 @@ find_file(const void *data, const char *name)
return NULL;
}
+static struct stH *
+sloffs_header(const void *data)
+{
+ struct sloffs *sloffs;
+ struct stH *header;
+
+ /* find the "header" file with all the information about
+ * the flash image */
+ sloffs = find_file(data, "header");
+ if (!sloffs) {
+ printf("sloffs file \"header\" not found. aborting...\n");
+ return NULL;
+ }
+
+ header = (struct stH *)((unsigned char *)sloffs +
+ be64_to_cpu(sloffs->data));
+ return header;
+}
+
+static uint64_t
+header_length(const void *data)
+{
+ struct sloffs *sloffs;
+
+ /* find the "header" file with all the information about
+ * the flash image */
+ sloffs = find_file(data, "header");
+ if (!sloffs) {
+ printf("sloffs file \"header\" not found. aborting...\n");
+ return 0;
+ }
+ return be64_to_cpu(sloffs->len);
+}
+
+
+static void
+update_modification_time(struct stH *header)
+{
+ struct tm *tm;
+ time_t caltime;
+ char dastr[16] = { 0, };
+ uint64_t date;
+
+ /* update modification date
+ * copied from create_crc.c */
+ caltime = time(NULL);
+ tm = localtime(&caltime);
+ strftime(dastr, 15, "0x%Y%m%d%H%M", tm);
+ date = cpu_to_be64(strtoll(dastr, NULL, 16));
+
+ /* this does not match the definition from
+ * struct stH, but we immitate the bug from
+ * flash image creation in create_crc.c.
+ * The date is in mdate and time in padding2. */
+ memcpy(&(header->mdate), &date, 8);
+}
+
+static void
+update_crc(void *data)
+{
+ uint64_t crc;
+ struct stH *header = sloffs_header(data);
+ uint64_t len = be64_to_cpu(header->flashlen);
+
+ /* calculate header CRC */
+ header->ui64CRC = 0;
+ crc = checkCRC(data, header_length(data), 0);
+ header->ui64CRC = cpu_to_be64(crc);
+ /* calculate flash image CRC */
+ crc = checkCRC(data, len, 0);
+ *(uint64_t *)(data + len - 8) = cpu_to_be64(crc);
+}
+
+static void
+sloffs_append(const void *data, const char *name, const char *dest)
+{
+ void *append;
+ unsigned char *write_data;
+ void *write_start;
+ int fd;
+ int out;
+ struct stat stat;
+ struct stH *header;
+ uint64_t new_len;
+ struct sloffs *sloffs;
+ struct sloffs new_file;
+
+ fd = open(name, O_RDONLY);
+
+ if (fd == -1) {
+ perror(name);
+ exit(1);
+ }
+
+ fstat(fd, &stat);
+ append = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ header = sloffs_header(data);
+
+ if (!header)
+ return;
+
+ new_len = ALIGN64(stat.st_size) + be64_to_cpu(header->flashlen);
+ /* add the length of the sloffs file meta information */
+ new_len += SLOFFS_META;
+ /* add the length of the filename */
+ new_len += ALIGN64(strlen(name) + 1);
+
+ out = open(dest, O_CREAT | O_RDWR | O_TRUNC, 00666);
+
+ if (out == -1) {
+ perror(dest);
+ exit(1);
+ }
+
+ /* write byte at the end to be able to mmap it */
+ lseek(out, new_len - 1, SEEK_SET);
+ write(out, "", 1);
+ write_start = mmap(NULL, new_len, PROT_READ | PROT_WRITE,
+ MAP_SHARED, out, 0);
+
+ memset(write_start, 0, new_len);
+ memset(&new_file, 0, sizeof(struct sloffs));
+
+ new_file.len = cpu_to_be64(stat.st_size);
+ new_file.data = cpu_to_be64(SLOFFS_META + ALIGN64(strlen(name) + 1));
+
+ if (write_start == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ write_data = memcpy(write_start, data, be64_to_cpu(header->flashlen));
+ /* -8: overwrite old CRC */
+ write_data += be64_to_cpu(header->flashlen) - 8;
+ memcpy(write_data, &new_file, SLOFFS_META);
+ write_data += SLOFFS_META;
+ /* write the filename */
+ memcpy(write_data, name, strlen(name));
+ write_data += ALIGN64(strlen(name) + 1 );
+ memcpy(write_data, append, stat.st_size);
+
+ write_data = write_start;
+
+ /* find last file */
+ sloffs = (struct sloffs *)write_start;
+ for (;;) {
+ if (be64_to_cpu(sloffs->next) == 0)
+ break;
+ sloffs = next_file(sloffs);
+ }
+ /* get the distance to the next file */
+ sloffs->next = ALIGN64(be64_to_cpu(sloffs->len));
+ /* and the offset were the data starts */
+ sloffs->next += be64_to_cpu(sloffs->data);
+ /* and we have to skip the end of file marker
+ * if one is there; if the last uint64_t is -1
+ * it is an end of file marker; this is a bit dangerous
+ * but there is no other way to detect the end of
+ * file marker */
+ if ((uint64_t)be64_to_cpu(*(uint64_t *)((unsigned char *)sloffs +
+ sloffs->next)) == (uint64_t)-1ULL)
+ sloffs->next += 8;
+
+ sloffs->next = cpu_to_be64(sloffs->next);
+
+ /* update new length of flash image */
+ header = sloffs_header(write_start);
+ header->flashlen = cpu_to_be64(new_len);
+
+ update_modification_time(header);
+
+ update_crc(write_start);
+
+ munmap(append, stat.st_size);
+ munmap(write_start, new_len);
+ close(fd);
+ close(out);
+}
+
static void
sloffs_dump(const void *data)
{
@@ -91,16 +276,10 @@ sloffs_dump(const void *data)
uint64_t crc;
uint64_t *datetmp;
- /* find the "header" file with all the information about
- * the flash image */
- sloffs = find_file(data, "header");
- if (!sloffs) {
- printf("sloffs file \"header\" not found. aborting...\n");
- return;
- }
+ header = sloffs_header(data);
- header = (struct stH *)((unsigned char *)sloffs +
- be64_to_cpu(sloffs->data));
+ if (!header)
+ return;
if (memcmp(FLASHFS_MAGIC, header->magic, strlen(FLASHFS_MAGIC))) {
printf("sloffs magic not found. "
@@ -141,7 +320,12 @@ sloffs_dump(const void *data)
printf(" Revision : %s\n", header->platform_revision);
crc = be64_to_cpu(header->ui64CRC);
printf(" Header CRC : 0x%016lx CRC check: ", crc);
- crc = calCRCword((unsigned char *)data, be64_to_cpu(sloffs->len), 0);
+ /* to test the CRC of the header we need to know the actual
+ * size of the file and not just the size of the data
+ * which could be easily obtained with sizeof(struct stH);
+ * the actual size can only be obtained from the filesystem
+ * meta information */
+ crc = calCRCword((unsigned char *)data, header_length(data), 0);
if (!crc)
printf("[OK]");
else
@@ -234,6 +418,11 @@ usage(void)
printf(" -l, --list list all files in the flash image\n");
printf(" -v, --version print the version, then exit\n");
printf(" -d, --dump dump the information from the header\n");
+ printf(" -a, --append=FILENAME append file at the end of\n");
+ printf(" the existing image\n");
+ printf(" -o, --output=FILENAME if appending a file this parameter\n");
+ printf(" is necessary to specify the name of\n");
+ printf(" the output file\n");
printf("\n");
exit(1);
}
@@ -249,11 +438,15 @@ main(int argc, char *argv[])
{ "list", 0, NULL, 'l' },
{ "version", 0, NULL, 'v' },
{ "dump", 0, NULL, 'd' },
+ { "append", 1, NULL, 'a' },
+ { "output", 1, NULL, 'o' },
{ 0, 0, 0, 0 }
};
- const char *soption = "dhlv";
+ const char *soption = "dhlva:o:";
int c;
char mode = 0;
+ char *append = NULL;
+ char *output = NULL;
for (;;) {
c = getopt_long(argc, argv, soption, loption, NULL);
@@ -269,6 +462,13 @@ main(int argc, char *argv[])
case 'd':
mode = 'd';
break;
+ case 'a':
+ mode = 'a';
+ append = strdup(optarg);
+ break;
+ case 'o':
+ output = strdup(optarg);
+ break;
case 'h':
default:
usage();
@@ -295,8 +495,18 @@ main(int argc, char *argv[])
case 'd':
sloffs_dump(file);
break;
+ case 'a':
+ if (!output) {
+ printf("sloffs requires -o, --output=FILENAME"
+ " when in append mode\n\n");
+ usage();
+ }
+ sloffs_append(file, append, output);
+ break;
}
+ free(append);
+ free(output);
munmap(file, stat.st_size);
close(fd);
return 0;