otrx: optimize memory usage when creating TRX image
[openwrt/openwrt.git] / package / utils / otrx / src / otrx.c
index 213f9599476d7331b4d64aa165ed4b34f09e2764..d08507f685cbbd4c8ab943826f1737c0a61dba9e 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <byteswap.h>
+#include <endian.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
 #if __BYTE_ORDER == __BIG_ENDIAN
 #define cpu_to_le32(x) bswap_32(x)
 #define le32_to_cpu(x) bswap_32(x)
@@ -44,6 +49,10 @@ char *trx_path;
 size_t trx_offset = 0;
 char *partition[TRX_MAX_PARTS] = {};
 
+static inline size_t otrx_min(size_t x, size_t y) {
+       return x < y ? x : y;
+}
+
 /**************************************************
  * CRC32
  **************************************************/
@@ -115,9 +124,7 @@ static const uint32_t crc32_tbl[] = {
        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
 };
 
-uint32_t otrx_crc32(uint8_t *buf, size_t len) {
-       uint32_t crc = 0xffffffff;
-
+uint32_t otrx_crc32(uint32_t crc, uint8_t *buf, size_t len) {
        while (len) {
                crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
                buf++;
@@ -147,7 +154,7 @@ static int otrx_check(int argc, char **argv) {
        FILE *trx;
        struct trx_header hdr;
        size_t bytes, length;
-       uint8_t *buf;
+       uint8_t buf[1024];
        uint32_t crc32;
        int err = 0;
 
@@ -189,32 +196,28 @@ static int otrx_check(int argc, char **argv) {
                goto err_close;
        }
 
-       buf = malloc(length);
-       if (!buf) {
-               fprintf(stderr, "Couldn't alloc %zd B buffer\n", length);
-               err =  -ENOMEM;
-               goto err_close;
+       crc32 = 0xffffffff;
+       fseek(trx, trx_offset + TRX_FLAGS_OFFSET, SEEK_SET);
+       length -= TRX_FLAGS_OFFSET;
+       while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
+               crc32 = otrx_crc32(crc32, buf, bytes);
+               length -= bytes;
        }
 
-       fseek(trx, trx_offset, SEEK_SET);
-       bytes = fread(buf, 1, length, trx);
-       if (bytes != length) {
-               fprintf(stderr, "Couldn't read %zd B of data from %s\n", length, trx_path);
-               err =  -ENOMEM;
-               goto err_free_buf;
+       if (length) {
+               fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path);
+               err = -EIO;
+               goto err_close;
        }
 
-       crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
        if (crc32 != le32_to_cpu(hdr.crc32)) {
                fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
                err =  -EINVAL;
-               goto err_free_buf;
+               goto err_close;
        }
 
        printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
 
-err_free_buf:
-       free(buf);
 err_close:
        fclose(trx);
 out:
@@ -281,7 +284,7 @@ static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment
 
 static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
        size_t bytes, length;
-       uint8_t *buf;
+       uint8_t buf[1024];
        uint32_t crc32;
 
        hdr->magic = cpu_to_le32(TRX_MAGIC);
@@ -296,20 +299,13 @@ static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
 
        length = le32_to_cpu(hdr->length);
 
-       buf = malloc(length);
-       if (!buf) {
-               fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
-               return -ENOMEM;
-       }
-
-       fseek(trx, 0, SEEK_SET);
-       bytes = fread(buf, 1, length, trx);
-       if (bytes != length) {
-               fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
-               return -ENOMEM;
+       crc32 = 0xffffffff;
+       fseek(trx, TRX_FLAGS_OFFSET, SEEK_SET);
+       length -= TRX_FLAGS_OFFSET;
+       while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
+               crc32 = otrx_crc32(crc32, buf, bytes);
+               length -= bytes;
        }
-
-       crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
        hdr->crc32 = cpu_to_le32(crc32);
 
        fseek(trx, 0, SEEK_SET);