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