summaryrefslogtreecommitdiff
path: root/src/dfu_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dfu_file.c')
-rw-r--r--src/dfu_file.c75
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) {