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