From patchwork Wed Jun 15 08:29:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adrian Reber X-Patchwork-Id: 636165 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rVR1t5lXqz9ssP for ; Thu, 16 Jun 2016 11:41:38 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3rVR1t51z4zDqlv for ; Thu, 16 Jun 2016 11:41:38 +1000 (AEST) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3rV0Fg6cY9zDqhl for ; Wed, 15 Jun 2016 18:35:19 +1000 (AEST) Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4110AC049D5C; Wed, 15 Jun 2016 08:35:18 +0000 (UTC) Received: from dcbz.localdomain (ovpn-116-49.ams2.redhat.com [10.36.116.49]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u5F8YPMF023485; Wed, 15 Jun 2016 04:35:16 -0400 From: Adrian Reber To: Alexey Kardashevskiy Date: Wed, 15 Jun 2016 10:29:56 +0200 Message-Id: <1465979400-2964-10-git-send-email-adrian@lisas.de> In-Reply-To: <1465979400-2964-1-git-send-email-adrian@lisas.de> References: <1465979400-2964-1-git-send-email-adrian@lisas.de> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Wed, 15 Jun 2016 08:35:18 +0000 (UTC) X-Mailman-Approved-At: Thu, 16 Jun 2016 11:41:14 +1000 Subject: [SLOF] [PATCH 09/13] tools: added file append functionality X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Thomas Huth , slof@lists.ozlabs.org, Adrian Reber MIME-Version: 1.0 Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" The -a, --append can now be used to append any file to flash image filesystem. It is required that -o, --output specifies an output file name. (cherry picked from commit 339c6f4d17cae84526c7cba63928bf7769de5abe) Cherry picked from https://lisas.de/~adrian/slof/slof.git/ Signed-off-by: Adrian Reber --- tools/sloffs.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 220 insertions(+), 12 deletions(-) diff --git a/tools/sloffs.c b/tools/sloffs.c index bd8ebd2..4db5cfe 100644 --- a/tools/sloffs.c +++ b/tools/sloffs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -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,24 +88,194 @@ find_file(const void *data, const char *name) return NULL; } -static void -sloffs_dump(const void *data) +static struct stH * +sloffs_header(const void *data) { - struct stH *header; struct sloffs *sloffs; - int i; - uint64_t crc; + 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; + 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, }; + + /* update modification date + * copied from create_crc.c */ + caltime = time(NULL); + tm = localtime(&caltime); + strftime(dastr, 15, "0x%Y%m%d%H%M", tm); + + /* this does not match the definition from + * struct stH, but we immitate the bug from + * flash image creation in create_crc.c */ + *(uint64_t *)(header->mdate) = cpu_to_be64(strtoll(dastr, NULL, 16)); +} + +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) +{ + struct stH *header; + struct sloffs *sloffs; + int i; + uint64_t crc; + + header = sloffs_header(data); + + if (!header) + return; if (memcmp(FLASHFS_MAGIC, header->magic, strlen(FLASHFS_MAGIC))) { printf("sloffs magic not found. " @@ -138,7 +314,12 @@ sloffs_dump(const void *data) printf(" Revision : %s\n", header->platform_revision); crc = be64_to_cpu(header->ui64CRC); printf(" Header CRC : 0x%016llx 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 @@ -227,10 +408,16 @@ usage(void) printf("Usage:\n"); printf(" sloffs [OPTION]... [FILE]\n\n"); printf("Options:\n"); - printf(" -h, --help show this help, then exit\n"); - printf(" -l, --list print a listing of all files in the image\n"); - printf(" -v, --version print the version, then exit\n"); - printf(" -d, --dump dump the information from the header\n"); + printf(" -h, --help show this help, then exit\n"); + printf( + " -l, --list print a listing of all files in the 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 the existing image\n"); + printf(" -o, --output=FILENAME if appending a file this parameter is\n"); + printf( + " to specify the name of the output file\n"); printf("\n"); exit(1); } @@ -246,11 +433,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); @@ -266,6 +457,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(); @@ -292,8 +490,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;