Back to home page

LXR

 
 

    


0001 /*
0002  * LZO decompressor for the Linux kernel. Code borrowed from the lzo
0003  * implementation by Markus Franz Xaver Johannes Oberhumer.
0004  *
0005  * Linux kernel adaptation:
0006  * Copyright (C) 2009
0007  * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
0008  *
0009  * Original code:
0010  * Copyright (C) 1996-2005 Markus Franz Xaver Johannes Oberhumer
0011  * All Rights Reserved.
0012  *
0013  * lzop and the LZO library are free software; you can redistribute them
0014  * and/or modify them under the terms of the GNU General Public License as
0015  * published by the Free Software Foundation; either version 2 of
0016  * the License, or (at your option) any later version.
0017  *
0018  * This program is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program; see the file COPYING.
0025  * If not, write to the Free Software Foundation, Inc.,
0026  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0027  *
0028  * Markus F.X.J. Oberhumer
0029  * <markus@oberhumer.com>
0030  * http://www.oberhumer.com/opensource/lzop/
0031  */
0032 
0033 #ifdef STATIC
0034 #define PREBOOT
0035 #include "lzo/lzo1x_decompress_safe.c"
0036 #else
0037 #include <linux/decompress/unlzo.h>
0038 #endif
0039 
0040 #include <linux/types.h>
0041 #include <linux/lzo.h>
0042 #include <linux/decompress/mm.h>
0043 
0044 #include <linux/compiler.h>
0045 #include <asm/unaligned.h>
0046 
0047 static const unsigned char lzop_magic[] = {
0048     0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a };
0049 
0050 #define LZO_BLOCK_SIZE        (256*1024l)
0051 #define HEADER_HAS_FILTER      0x00000800L
0052 #define HEADER_SIZE_MIN       (9 + 7     + 4 + 8     + 1       + 4)
0053 #define HEADER_SIZE_MAX       (9 + 7 + 1 + 8 + 8 + 4 + 1 + 255 + 4)
0054 
0055 STATIC inline long INIT parse_header(u8 *input, long *skip, long in_len)
0056 {
0057     int l;
0058     u8 *parse = input;
0059     u8 *end = input + in_len;
0060     u8 level = 0;
0061     u16 version;
0062 
0063     /*
0064      * Check that there's enough input to possibly have a valid header.
0065      * Then it is possible to parse several fields until the minimum
0066      * size may have been used.
0067      */
0068     if (in_len < HEADER_SIZE_MIN)
0069         return 0;
0070 
0071     /* read magic: 9 first bits */
0072     for (l = 0; l < 9; l++) {
0073         if (*parse++ != lzop_magic[l])
0074             return 0;
0075     }
0076     /* get version (2bytes), skip library version (2),
0077      * 'need to be extracted' version (2) and
0078      * method (1) */
0079     version = get_unaligned_be16(parse);
0080     parse += 7;
0081     if (version >= 0x0940)
0082         level = *parse++;
0083     if (get_unaligned_be32(parse) & HEADER_HAS_FILTER)
0084         parse += 8; /* flags + filter info */
0085     else
0086         parse += 4; /* flags */
0087 
0088     /*
0089      * At least mode, mtime_low, filename length, and checksum must
0090      * be left to be parsed. If also mtime_high is present, it's OK
0091      * because the next input buffer check is after reading the
0092      * filename length.
0093      */
0094     if (end - parse < 8 + 1 + 4)
0095         return 0;
0096 
0097     /* skip mode and mtime_low */
0098     parse += 8;
0099     if (version >= 0x0940)
0100         parse += 4; /* skip mtime_high */
0101 
0102     l = *parse++;
0103     /* don't care about the file name, and skip checksum */
0104     if (end - parse < l + 4)
0105         return 0;
0106     parse += l + 4;
0107 
0108     *skip = parse - input;
0109     return 1;
0110 }
0111 
0112 STATIC int INIT unlzo(u8 *input, long in_len,
0113                 long (*fill)(void *, unsigned long),
0114                 long (*flush)(void *, unsigned long),
0115                 u8 *output, long *posp,
0116                 void (*error) (char *x))
0117 {
0118     u8 r = 0;
0119     long skip = 0;
0120     u32 src_len, dst_len;
0121     size_t tmp;
0122     u8 *in_buf, *in_buf_save, *out_buf;
0123     int ret = -1;
0124 
0125     if (output) {
0126         out_buf = output;
0127     } else if (!flush) {
0128         error("NULL output pointer and no flush function provided");
0129         goto exit;
0130     } else {
0131         out_buf = malloc(LZO_BLOCK_SIZE);
0132         if (!out_buf) {
0133             error("Could not allocate output buffer");
0134             goto exit;
0135         }
0136     }
0137 
0138     if (input && fill) {
0139         error("Both input pointer and fill function provided, don't know what to do");
0140         goto exit_1;
0141     } else if (input) {
0142         in_buf = input;
0143     } else if (!fill) {
0144         error("NULL input pointer and missing fill function");
0145         goto exit_1;
0146     } else {
0147         in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
0148         if (!in_buf) {
0149             error("Could not allocate input buffer");
0150             goto exit_1;
0151         }
0152     }
0153     in_buf_save = in_buf;
0154 
0155     if (posp)
0156         *posp = 0;
0157 
0158     if (fill) {
0159         /*
0160          * Start from in_buf + HEADER_SIZE_MAX to make it possible
0161          * to use memcpy() to copy the unused data to the beginning
0162          * of the buffer. This way memmove() isn't needed which
0163          * is missing from pre-boot environments of most archs.
0164          */
0165         in_buf += HEADER_SIZE_MAX;
0166         in_len = fill(in_buf, HEADER_SIZE_MAX);
0167     }
0168 
0169     if (!parse_header(in_buf, &skip, in_len)) {
0170         error("invalid header");
0171         goto exit_2;
0172     }
0173     in_buf += skip;
0174     in_len -= skip;
0175 
0176     if (fill) {
0177         /* Move the unused data to the beginning of the buffer. */
0178         memcpy(in_buf_save, in_buf, in_len);
0179         in_buf = in_buf_save;
0180     }
0181 
0182     if (posp)
0183         *posp = skip;
0184 
0185     for (;;) {
0186         /* read uncompressed block size */
0187         if (fill && in_len < 4) {
0188             skip = fill(in_buf + in_len, 4 - in_len);
0189             if (skip > 0)
0190                 in_len += skip;
0191         }
0192         if (in_len < 4) {
0193             error("file corrupted");
0194             goto exit_2;
0195         }
0196         dst_len = get_unaligned_be32(in_buf);
0197         in_buf += 4;
0198         in_len -= 4;
0199 
0200         /* exit if last block */
0201         if (dst_len == 0) {
0202             if (posp)
0203                 *posp += 4;
0204             break;
0205         }
0206 
0207         if (dst_len > LZO_BLOCK_SIZE) {
0208             error("dest len longer than block size");
0209             goto exit_2;
0210         }
0211 
0212         /* read compressed block size, and skip block checksum info */
0213         if (fill && in_len < 8) {
0214             skip = fill(in_buf + in_len, 8 - in_len);
0215             if (skip > 0)
0216                 in_len += skip;
0217         }
0218         if (in_len < 8) {
0219             error("file corrupted");
0220             goto exit_2;
0221         }
0222         src_len = get_unaligned_be32(in_buf);
0223         in_buf += 8;
0224         in_len -= 8;
0225 
0226         if (src_len <= 0 || src_len > dst_len) {
0227             error("file corrupted");
0228             goto exit_2;
0229         }
0230 
0231         /* decompress */
0232         if (fill && in_len < src_len) {
0233             skip = fill(in_buf + in_len, src_len - in_len);
0234             if (skip > 0)
0235                 in_len += skip;
0236         }
0237         if (in_len < src_len) {
0238             error("file corrupted");
0239             goto exit_2;
0240         }
0241         tmp = dst_len;
0242 
0243         /* When the input data is not compressed at all,
0244          * lzo1x_decompress_safe will fail, so call memcpy()
0245          * instead */
0246         if (unlikely(dst_len == src_len))
0247             memcpy(out_buf, in_buf, src_len);
0248         else {
0249             r = lzo1x_decompress_safe((u8 *) in_buf, src_len,
0250                         out_buf, &tmp);
0251 
0252             if (r != LZO_E_OK || dst_len != tmp) {
0253                 error("Compressed data violation");
0254                 goto exit_2;
0255             }
0256         }
0257 
0258         if (flush && flush(out_buf, dst_len) != dst_len)
0259             goto exit_2;
0260         if (output)
0261             out_buf += dst_len;
0262         if (posp)
0263             *posp += src_len + 12;
0264 
0265         in_buf += src_len;
0266         in_len -= src_len;
0267         if (fill) {
0268             /*
0269              * If there happens to still be unused data left in
0270              * in_buf, move it to the beginning of the buffer.
0271              * Use a loop to avoid memmove() dependency.
0272              */
0273             if (in_len > 0)
0274                 for (skip = 0; skip < in_len; ++skip)
0275                     in_buf_save[skip] = in_buf[skip];
0276             in_buf = in_buf_save;
0277         }
0278     }
0279 
0280     ret = 0;
0281 exit_2:
0282     if (!input)
0283         free(in_buf_save);
0284 exit_1:
0285     if (!output)
0286         free(out_buf);
0287 exit:
0288     return ret;
0289 }
0290 
0291 #ifdef PREBOOT
0292 STATIC int INIT __decompress(unsigned char *buf, long len,
0293                long (*fill)(void*, unsigned long),
0294                long (*flush)(void*, unsigned long),
0295                unsigned char *out_buf, long olen,
0296                long *pos,
0297                void (*error)(char *x))
0298 {
0299     return unlzo(buf, len, fill, flush, out_buf, pos, error);
0300 }
0301 #endif