uboot/lib/gunzip.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000-2006
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <console.h>
  10#include <div64.h>
  11#include <gzip.h>
  12#include <image.h>
  13#include <malloc.h>
  14#include <memalign.h>
  15#include <u-boot/crc.h>
  16#include <watchdog.h>
  17#include <u-boot/zlib.h>
  18
  19#define HEADER0                 '\x1f'
  20#define HEADER1                 '\x8b'
  21#define ZALLOC_ALIGNMENT        16
  22#define HEAD_CRC                2
  23#define EXTRA_FIELD             4
  24#define ORIG_NAME               8
  25#define COMMENT                 0x10
  26#define RESERVED                0xe0
  27#define DEFLATED                8
  28
  29void *gzalloc(void *x, unsigned items, unsigned size)
  30{
  31        void *p;
  32
  33        size *= items;
  34        size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
  35
  36        p = malloc (size);
  37
  38        return (p);
  39}
  40
  41void gzfree(void *x, void *addr, unsigned nb)
  42{
  43        free (addr);
  44}
  45
  46int gzip_parse_header(const unsigned char *src, unsigned long len)
  47{
  48        int i, flags;
  49
  50        /* skip header */
  51        i = 10;
  52        flags = src[3];
  53        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  54                puts ("Error: Bad gzipped data\n");
  55                return (-1);
  56        }
  57        if ((flags & EXTRA_FIELD) != 0)
  58                i = 12 + src[10] + (src[11] << 8);
  59        if ((flags & ORIG_NAME) != 0)
  60                while (src[i++] != 0)
  61                        ;
  62        if ((flags & COMMENT) != 0)
  63                while (src[i++] != 0)
  64                        ;
  65        if ((flags & HEAD_CRC) != 0)
  66                i += 2;
  67        if (i >= len) {
  68                puts ("Error: gunzip out of data in header\n");
  69                return (-1);
  70        }
  71        return i;
  72}
  73
  74int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
  75{
  76        int offset = gzip_parse_header(src, *lenp);
  77
  78        if (offset < 0)
  79                return offset;
  80
  81        return zunzip(dst, dstlen, src, lenp, 1, offset);
  82}
  83
  84#ifdef CONFIG_CMD_UNZIP
  85__weak
  86void gzwrite_progress_init(u64 expectedsize)
  87{
  88        putc('\n');
  89}
  90
  91__weak
  92void gzwrite_progress(int iteration,
  93                     u64 bytes_written,
  94                     u64 total_bytes)
  95{
  96        if (0 == (iteration & 3))
  97                printf("%llu/%llu\r", bytes_written, total_bytes);
  98}
  99
 100__weak
 101void gzwrite_progress_finish(int returnval,
 102                             u64 bytes_written,
 103                             u64 total_bytes,
 104                             u32 expected_crc,
 105                             u32 calculated_crc)
 106{
 107        if (0 == returnval) {
 108                printf("\n\t%llu bytes, crc 0x%08x\n",
 109                       total_bytes, calculated_crc);
 110        } else {
 111                printf("\n\tuncompressed %llu of %llu\n"
 112                       "\tcrcs == 0x%08x/0x%08x\n",
 113                       bytes_written, total_bytes,
 114                       expected_crc, calculated_crc);
 115        }
 116}
 117
 118int gzwrite(unsigned char *src, int len,
 119            struct blk_desc *dev,
 120            unsigned long szwritebuf,
 121            u64 startoffs,
 122            u64 szexpected)
 123{
 124        int i, flags;
 125        z_stream s;
 126        int r = 0;
 127        unsigned char *writebuf;
 128        unsigned crc = 0;
 129        u64 totalfilled = 0;
 130        lbaint_t blksperbuf, outblock;
 131        u32 expected_crc;
 132        u32 payload_size;
 133        int iteration = 0;
 134
 135        if (!szwritebuf ||
 136            (szwritebuf % dev->blksz) ||
 137            (szwritebuf < dev->blksz)) {
 138                printf("%s: size %lu not a multiple of %lu\n",
 139                       __func__, szwritebuf, dev->blksz);
 140                return -1;
 141        }
 142
 143        if (startoffs & (dev->blksz-1)) {
 144                printf("%s: start offset %llu not a multiple of %lu\n",
 145                       __func__, startoffs, dev->blksz);
 146                return -1;
 147        }
 148
 149        blksperbuf = szwritebuf / dev->blksz;
 150        outblock = lldiv(startoffs, dev->blksz);
 151
 152        /* skip header */
 153        i = 10;
 154        flags = src[3];
 155        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
 156                puts("Error: Bad gzipped data\n");
 157                return -1;
 158        }
 159        if ((flags & EXTRA_FIELD) != 0)
 160                i = 12 + src[10] + (src[11] << 8);
 161        if ((flags & ORIG_NAME) != 0)
 162                while (src[i++] != 0)
 163                        ;
 164        if ((flags & COMMENT) != 0)
 165                while (src[i++] != 0)
 166                        ;
 167        if ((flags & HEAD_CRC) != 0)
 168                i += 2;
 169
 170        if (i >= len-8) {
 171                puts("Error: gunzip out of data in header");
 172                return -1;
 173        }
 174
 175        payload_size = len - i - 8;
 176
 177        memcpy(&expected_crc, src + len - 8, sizeof(expected_crc));
 178        expected_crc = le32_to_cpu(expected_crc);
 179        u32 szuncompressed;
 180        memcpy(&szuncompressed, src + len - 4, sizeof(szuncompressed));
 181        if (szexpected == 0) {
 182                szexpected = le32_to_cpu(szuncompressed);
 183        } else if (szuncompressed != (u32)szexpected) {
 184                printf("size of %llx doesn't match trailer low bits %x\n",
 185                       szexpected, szuncompressed);
 186                return -1;
 187        }
 188        if (lldiv(szexpected, dev->blksz) > (dev->lba - outblock)) {
 189                printf("%s: uncompressed size %llu exceeds device size\n",
 190                       __func__, szexpected);
 191                return -1;
 192        }
 193
 194        gzwrite_progress_init(szexpected);
 195
 196        s.zalloc = gzalloc;
 197        s.zfree = gzfree;
 198
 199        r = inflateInit2(&s, -MAX_WBITS);
 200        if (r != Z_OK) {
 201                printf("Error: inflateInit2() returned %d\n", r);
 202                return -1;
 203        }
 204
 205        s.next_in = src + i;
 206        s.avail_in = payload_size+8;
 207        writebuf = (unsigned char *)malloc_cache_aligned(szwritebuf);
 208
 209        /* decompress until deflate stream ends or end of file */
 210        do {
 211                if (s.avail_in == 0) {
 212                        printf("%s: weird termination with result %d\n",
 213                               __func__, r);
 214                        break;
 215                }
 216
 217                /* run inflate() on input until output buffer not full */
 218                do {
 219                        unsigned long blocks_written;
 220                        int numfilled;
 221                        lbaint_t writeblocks;
 222
 223                        s.avail_out = szwritebuf;
 224                        s.next_out = writebuf;
 225                        r = inflate(&s, Z_SYNC_FLUSH);
 226                        if ((r != Z_OK) &&
 227                            (r != Z_STREAM_END)) {
 228                                printf("Error: inflate() returned %d\n", r);
 229                                goto out;
 230                        }
 231                        numfilled = szwritebuf - s.avail_out;
 232                        crc = crc32(crc, writebuf, numfilled);
 233                        totalfilled += numfilled;
 234                        if (numfilled < szwritebuf) {
 235                                writeblocks = (numfilled+dev->blksz-1)
 236                                                / dev->blksz;
 237                                memset(writebuf+numfilled, 0,
 238                                       dev->blksz-(numfilled%dev->blksz));
 239                        } else {
 240                                writeblocks = blksperbuf;
 241                        }
 242
 243                        gzwrite_progress(iteration++,
 244                                         totalfilled,
 245                                         szexpected);
 246                        blocks_written = blk_dwrite(dev, outblock,
 247                                                    writeblocks, writebuf);
 248                        outblock += blocks_written;
 249                        if (ctrlc()) {
 250                                puts("abort\n");
 251                                goto out;
 252                        }
 253                        WATCHDOG_RESET();
 254                } while (s.avail_out == 0);
 255                /* done when inflate() says it's done */
 256        } while (r != Z_STREAM_END);
 257
 258        if ((szexpected != totalfilled) ||
 259            (crc != expected_crc))
 260                r = -1;
 261        else
 262                r = 0;
 263
 264out:
 265        gzwrite_progress_finish(r, totalfilled, szexpected,
 266                                expected_crc, crc);
 267        free(writebuf);
 268        inflateEnd(&s);
 269
 270        return r;
 271}
 272#endif
 273
 274/*
 275 * Uncompress blocks compressed with zlib without headers
 276 */
 277int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp,
 278                                                int stoponerr, int offset)
 279{
 280        z_stream s;
 281        int err = 0;
 282        int r;
 283
 284        s.zalloc = gzalloc;
 285        s.zfree = gzfree;
 286
 287        r = inflateInit2(&s, -MAX_WBITS);
 288        if (r != Z_OK) {
 289                printf("Error: inflateInit2() returned %d\n", r);
 290                return -1;
 291        }
 292        s.next_in = src + offset;
 293        s.avail_in = *lenp - offset;
 294        s.next_out = dst;
 295        s.avail_out = dstlen;
 296        do {
 297                r = inflate(&s, Z_FINISH);
 298                if (stoponerr == 1 && r != Z_STREAM_END &&
 299                    (s.avail_in == 0 || s.avail_out == 0 || r != Z_BUF_ERROR)) {
 300                        printf("Error: inflate() returned %d\n", r);
 301                        err = -1;
 302                        break;
 303                }
 304        } while (r == Z_BUF_ERROR);
 305        *lenp = s.next_out - (unsigned char *) dst;
 306        inflateEnd(&s);
 307
 308        return err;
 309}
 310