diff options
Diffstat (limited to 'src/dfu_file.c')
-rw-r--r-- | src/dfu_file.c | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/src/dfu_file.c b/src/dfu_file.c index 7c897d4..dbe7374 100644 --- a/src/dfu_file.c +++ b/src/dfu_file.c @@ -1,7 +1,7 @@ /* * Load or store DFU files including suffix and prefix * - * Copyright 2014 Tormod Volden <debian.tormod@gmail.com> + * Copyright 2014-2019 Tormod Volden <debian.tormod@gmail.com> * Copyright 2012 Stefan Schmidt <stefan@datenfreihafen.org> * * This program is free software; you can redistribute it and/or modify @@ -19,6 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define __USE_MINGW_ANSI_STDIO 1 #include <stdio.h> #include <string.h> #include <errno.h> @@ -26,6 +31,7 @@ #include <stdlib.h> #include <time.h> #include <fcntl.h> +#include <limits.h> #include "portable.h" #include "dfu_file.h" @@ -93,6 +99,11 @@ static int probe_prefix(struct dfu_file *file) if (file->size.total < LMDFU_PREFIX_LENGTH) return 1; if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) { + uint32_t payload_length = (prefix[7] << 24) | (prefix[6] << 16) | + (prefix[5] << 8) | prefix[4]; + uint32_t expected_payload_length = (uint32_t) file->size.total - LMDFU_PREFIX_LENGTH - file->size.suffix; + if (payload_length != expected_payload_length) + return 1; file->prefix_type = LMDFU_PREFIX; file->size.prefix = LMDFU_PREFIX_LENGTH; file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]); @@ -142,7 +153,7 @@ void dfu_progress_bar(const char *desc, unsigned long long curr, } buf[x] = 0; - printf("\r%s\t[%s] %3lld%% %12lld bytes", desc, buf, + printf("\r%s\t[%s] %3llu%% %12llu bytes", desc, buf, (100ULL * curr) / max, curr); if (progress == PROGRESS_BAR_WIDTH) @@ -194,7 +205,7 @@ void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum pre free(file->firmware); if (!strcmp(file->name, "-")) { - int read_bytes; + size_t read_bytes; #ifdef WIN32 _setmode( _fileno( stdin ), _O_BINARY ); @@ -205,33 +216,52 @@ void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum pre while (read_bytes == STDIN_CHUNK_SIZE) { file->firmware = (uint8_t*) realloc(file->firmware, file->size.total + STDIN_CHUNK_SIZE); if (!file->firmware) - err(EX_IOERR, "Could not allocate firmware buffer"); + err(EX_SOFTWARE, "Could not allocate firmware buffer"); read_bytes = fread(file->firmware + file->size.total, 1, STDIN_CHUNK_SIZE, stdin); file->size.total += read_bytes; } if (verbose) - printf("Read %i bytes from stdin\n", file->size.total); + printf("Read %lli bytes from stdin\n", (long long) file->size.total); /* Never require suffix when reading from stdin */ check_suffix = MAYBE_SUFFIX; } else { + ssize_t read_count; + off_t read_total = 0; + f = open(file->name, O_RDONLY | O_BINARY); if (f < 0) - err(EX_IOERR, "Could not open file %s for reading", file->name); + err(EX_NOINPUT, "Could not open file %s for reading", file->name); offset = lseek(f, 0, SEEK_END); - if ((int)offset < 0 || (int)offset != offset) - err(EX_IOERR, "File size is too big"); + if (offset < 0) + err(EX_SOFTWARE, "File size is too big"); if (lseek(f, 0, SEEK_SET) != 0) err(EX_IOERR, "Could not seek to beginning"); file->size.total = offset; + + if (file->size.total > SSIZE_MAX) { + err(EX_SOFTWARE, "File too large for memory allocation on this platform"); + } file->firmware = dfu_malloc(file->size.total); - if (read(f, file->firmware, file->size.total) != file->size.total) { - err(EX_IOERR, "Could not read %d bytes from %s", - file->size.total, file->name); + while (read_total < file->size.total) { + off_t to_read = file->size.total - read_total; + /* read() limit on Linux, slightly below MAX_INT on Windows */ + if (to_read > 0x7ffff000) + to_read = 0x7ffff000; + read_count = read(f, file->firmware + read_total, to_read); + if (read_count == 0) + break; + if (read_count == -1 && errno != EINTR) + break; + read_total += read_count; + } + if (read_total != file->size.total) { + err(EX_IOERR, "Could only read %lld of %lld bytes from %s", + (long long) read_total, (long long) file->size.total, file->name); } close(f); } @@ -285,12 +315,12 @@ void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum pre file->size.suffix = dfusuffix[11]; if (file->size.suffix < DFU_SUFFIX_LENGTH) { - errx(EX_IOERR, "Unsupported DFU suffix length %d", + errx(EX_DATAERR, "Unsupported DFU suffix length %d", file->size.suffix); } if (file->size.suffix > file->size.total) { - errx(EX_IOERR, "Invalid DFU suffix length %d", + errx(EX_DATAERR, "Invalid DFU suffix length %d", file->size.suffix); } @@ -302,23 +332,22 @@ checked: if (missing_suffix) { if (check_suffix == NEEDS_SUFFIX) { warnx("%s", reason); - errx(EX_IOERR, "Valid DFU suffix needed"); + errx(EX_DATAERR, "Valid DFU suffix needed"); } else if (check_suffix == MAYBE_SUFFIX) { - warnx("%s", reason); - warnx("A valid DFU suffix will be required in " - "a future dfu-util release!!!"); + warnx("Warning: %s", reason); + warnx("A valid DFU suffix will be required in a future dfu-util release"); } } else { if (check_suffix == NO_SUFFIX) { - errx(EX_SOFTWARE, "Please remove existing DFU suffix before adding a new one.\n"); + errx(EX_DATAERR, "Please remove existing DFU suffix before adding a new one.\n"); } } } res = probe_prefix(file); if ((res || file->size.prefix == 0) && check_prefix == NEEDS_PREFIX) - errx(EX_IOERR, "Valid DFU prefix needed"); + errx(EX_DATAERR, "Valid DFU prefix needed"); if (file->size.prefix && check_prefix == NO_PREFIX) - errx(EX_IOERR, "A prefix already exists, please delete it first"); + errx(EX_DATAERR, "A prefix already exists, please delete it first"); if (file->size.prefix && verbose) { uint8_t *data = file->firmware; if (file->prefix_type == LMDFU_PREFIX) @@ -328,14 +357,14 @@ checked: "Payload length: %d\n", file->lmdfu_address, data[4] | (data[5] << 8) | - (data[6] << 16) | (data[7] << 14)); + (data[6] << 16) | (data[7] << 24)); else if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) printf("Possible unencrypted NXP LPC DFU prefix with " "the following properties\n" "Payload length: %d kiByte\n", data[2] >>1 | (data[3] << 7) ); else - errx(EX_IOERR, "Unknown DFU prefix type"); + errx(EX_DATAERR, "Unknown DFU prefix type"); } } @@ -346,7 +375,7 @@ void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix) f = open(file->name, O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, 0666); if (f < 0) - err(EX_IOERR, "Could not open file %s for writing", file->name); + err(EX_CANTCREAT, "Could not open file %s for writing", file->name); /* write prefix, if any */ if (write_prefix) { |