0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #ifdef STATIC
0020 #define PREBOOT
0021 #include "lzo/lzo1x_decompress_safe.c"
0022 #else
0023 #include <linux/decompress/unlzo.h>
0024 #endif
0025
0026 #include <linux/types.h>
0027 #include <linux/lzo.h>
0028 #include <linux/decompress/mm.h>
0029
0030 #include <linux/compiler.h>
0031 #include <asm/unaligned.h>
0032
0033 static const unsigned char lzop_magic[] = {
0034 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a };
0035
0036 #define LZO_BLOCK_SIZE (256*1024l)
0037 #define HEADER_HAS_FILTER 0x00000800L
0038 #define HEADER_SIZE_MIN (9 + 7 + 4 + 8 + 1 + 4)
0039 #define HEADER_SIZE_MAX (9 + 7 + 1 + 8 + 8 + 4 + 1 + 255 + 4)
0040
0041 STATIC inline long INIT parse_header(u8 *input, long *skip, long in_len)
0042 {
0043 int l;
0044 u8 *parse = input;
0045 u8 *end = input + in_len;
0046 u16 version;
0047
0048
0049
0050
0051
0052
0053 if (in_len < HEADER_SIZE_MIN)
0054 return 0;
0055
0056
0057 for (l = 0; l < 9; l++) {
0058 if (*parse++ != lzop_magic[l])
0059 return 0;
0060 }
0061
0062
0063
0064 version = get_unaligned_be16(parse);
0065 parse += 7;
0066 if (version >= 0x0940)
0067 parse++;
0068 if (get_unaligned_be32(parse) & HEADER_HAS_FILTER)
0069 parse += 8;
0070 else
0071 parse += 4;
0072
0073
0074
0075
0076
0077
0078
0079 if (end - parse < 8 + 1 + 4)
0080 return 0;
0081
0082
0083 parse += 8;
0084 if (version >= 0x0940)
0085 parse += 4;
0086
0087 l = *parse++;
0088
0089 if (end - parse < l + 4)
0090 return 0;
0091 parse += l + 4;
0092
0093 *skip = parse - input;
0094 return 1;
0095 }
0096
0097 STATIC int INIT unlzo(u8 *input, long in_len,
0098 long (*fill)(void *, unsigned long),
0099 long (*flush)(void *, unsigned long),
0100 u8 *output, long *posp,
0101 void (*error) (char *x))
0102 {
0103 u8 r = 0;
0104 long skip = 0;
0105 u32 src_len, dst_len;
0106 size_t tmp;
0107 u8 *in_buf, *in_buf_save, *out_buf;
0108 int ret = -1;
0109
0110 if (output) {
0111 out_buf = output;
0112 } else if (!flush) {
0113 error("NULL output pointer and no flush function provided");
0114 goto exit;
0115 } else {
0116 out_buf = malloc(LZO_BLOCK_SIZE);
0117 if (!out_buf) {
0118 error("Could not allocate output buffer");
0119 goto exit;
0120 }
0121 }
0122
0123 if (input && fill) {
0124 error("Both input pointer and fill function provided, don't know what to do");
0125 goto exit_1;
0126 } else if (input) {
0127 in_buf = input;
0128 } else if (!fill) {
0129 error("NULL input pointer and missing fill function");
0130 goto exit_1;
0131 } else {
0132 in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
0133 if (!in_buf) {
0134 error("Could not allocate input buffer");
0135 goto exit_1;
0136 }
0137 }
0138 in_buf_save = in_buf;
0139
0140 if (posp)
0141 *posp = 0;
0142
0143 if (fill) {
0144
0145
0146
0147
0148
0149
0150 in_buf += HEADER_SIZE_MAX;
0151 in_len = fill(in_buf, HEADER_SIZE_MAX);
0152 }
0153
0154 if (!parse_header(in_buf, &skip, in_len)) {
0155 error("invalid header");
0156 goto exit_2;
0157 }
0158 in_buf += skip;
0159 in_len -= skip;
0160
0161 if (fill) {
0162
0163 memcpy(in_buf_save, in_buf, in_len);
0164 in_buf = in_buf_save;
0165 }
0166
0167 if (posp)
0168 *posp = skip;
0169
0170 for (;;) {
0171
0172 if (fill && in_len < 4) {
0173 skip = fill(in_buf + in_len, 4 - in_len);
0174 if (skip > 0)
0175 in_len += skip;
0176 }
0177 if (in_len < 4) {
0178 error("file corrupted");
0179 goto exit_2;
0180 }
0181 dst_len = get_unaligned_be32(in_buf);
0182 in_buf += 4;
0183 in_len -= 4;
0184
0185
0186 if (dst_len == 0) {
0187 if (posp)
0188 *posp += 4;
0189 break;
0190 }
0191
0192 if (dst_len > LZO_BLOCK_SIZE) {
0193 error("dest len longer than block size");
0194 goto exit_2;
0195 }
0196
0197
0198 if (fill && in_len < 8) {
0199 skip = fill(in_buf + in_len, 8 - in_len);
0200 if (skip > 0)
0201 in_len += skip;
0202 }
0203 if (in_len < 8) {
0204 error("file corrupted");
0205 goto exit_2;
0206 }
0207 src_len = get_unaligned_be32(in_buf);
0208 in_buf += 8;
0209 in_len -= 8;
0210
0211 if (src_len <= 0 || src_len > dst_len) {
0212 error("file corrupted");
0213 goto exit_2;
0214 }
0215
0216
0217 if (fill && in_len < src_len) {
0218 skip = fill(in_buf + in_len, src_len - in_len);
0219 if (skip > 0)
0220 in_len += skip;
0221 }
0222 if (in_len < src_len) {
0223 error("file corrupted");
0224 goto exit_2;
0225 }
0226 tmp = dst_len;
0227
0228
0229
0230
0231 if (unlikely(dst_len == src_len))
0232 memcpy(out_buf, in_buf, src_len);
0233 else {
0234 r = lzo1x_decompress_safe((u8 *) in_buf, src_len,
0235 out_buf, &tmp);
0236
0237 if (r != LZO_E_OK || dst_len != tmp) {
0238 error("Compressed data violation");
0239 goto exit_2;
0240 }
0241 }
0242
0243 if (flush && flush(out_buf, dst_len) != dst_len)
0244 goto exit_2;
0245 if (output)
0246 out_buf += dst_len;
0247 if (posp)
0248 *posp += src_len + 12;
0249
0250 in_buf += src_len;
0251 in_len -= src_len;
0252 if (fill) {
0253
0254
0255
0256
0257
0258 if (in_len > 0)
0259 for (skip = 0; skip < in_len; ++skip)
0260 in_buf_save[skip] = in_buf[skip];
0261 in_buf = in_buf_save;
0262 }
0263 }
0264
0265 ret = 0;
0266 exit_2:
0267 if (!input)
0268 free(in_buf_save);
0269 exit_1:
0270 if (!output)
0271 free(out_buf);
0272 exit:
0273 return ret;
0274 }
0275
0276 #ifdef PREBOOT
0277 STATIC int INIT __decompress(unsigned char *buf, long len,
0278 long (*fill)(void*, unsigned long),
0279 long (*flush)(void*, unsigned long),
0280 unsigned char *out_buf, long olen,
0281 long *pos,
0282 void (*error)(char *x))
0283 {
0284 return unlzo(buf, len, fill, flush, out_buf, pos, error);
0285 }
0286 #endif