Blame view
lib/decompress_unlz4.c
4.13 KB
e76e1fdfa lib: add support ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd * * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifdef STATIC #define PREBOOT #include "lz4/lz4_decompress.c" #else #include <linux/decompress/unlz4.h> #endif #include <linux/types.h> #include <linux/lz4.h> #include <linux/decompress/mm.h> #include <linux/compiler.h> #include <asm/unaligned.h> /* * Note: Uncompressed chunk size is used in the compressor side * (userspace side for compression). * It is hardcoded because there is not proper way to extract it * from the binary stream which is generated by the preliminary * version of LZ4 tool so far. */ #define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20) #define ARCHIVE_MAGICNUMBER 0x184C2102 |
d97b07c54 initramfs: suppor... |
33 34 35 36 |
STATIC inline int INIT unlz4(u8 *input, long in_len, long (*fill)(void *, unsigned long), long (*flush)(void *, unsigned long), u8 *output, long *posp, |
e76e1fdfa lib: add support ... |
37 38 39 40 41 42 43 44 |
void (*error) (char *x)) { int ret = -1; size_t chunksize = 0; size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE; u8 *inp; u8 *inp_start; u8 *outp; |
d97b07c54 initramfs: suppor... |
45 |
long size = in_len; |
e76e1fdfa lib: add support ... |
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
#ifdef PREBOOT size_t out_len = get_unaligned_le32(input + in_len); #endif size_t dest_len; if (output) { outp = output; } else if (!flush) { error("NULL output pointer and no flush function provided"); goto exit_0; } else { outp = large_malloc(uncomp_chunksize); if (!outp) { error("Could not allocate output buffer"); goto exit_0; } } if (input && fill) { error("Both input pointer and fill function provided,"); goto exit_1; } else if (input) { inp = input; } else if (!fill) { error("NULL input pointer and missing fill function"); goto exit_1; } else { inp = large_malloc(lz4_compressbound(uncomp_chunksize)); if (!inp) { error("Could not allocate input buffer"); goto exit_1; } } inp_start = inp; if (posp) *posp = 0; |
4d4b866ae initrd: fix lz4 d... |
84 85 86 87 88 89 90 |
if (fill) { size = fill(inp, 4); if (size < 4) { error("data corrupted"); goto exit_2; } } |
e76e1fdfa lib: add support ... |
91 92 93 |
chunksize = get_unaligned_le32(inp); if (chunksize == ARCHIVE_MAGICNUMBER) { |
4d4b866ae initrd: fix lz4 d... |
94 95 96 97 |
if (!fill) { inp += 4; size -= 4; } |
e76e1fdfa lib: add support ... |
98 99 100 101 102 103 104 105 106 |
} else { error("invalid header"); goto exit_2; } if (posp) *posp += 4; for (;;) { |
4d4b866ae initrd: fix lz4 d... |
107 108 109 110 111 112 113 114 115 |
if (fill) { size = fill(inp, 4); if (size == 0) break; if (size < 4) { error("data corrupted"); goto exit_2; } } |
e76e1fdfa lib: add support ... |
116 117 118 |
chunksize = get_unaligned_le32(inp); if (chunksize == ARCHIVE_MAGICNUMBER) { |
4d4b866ae initrd: fix lz4 d... |
119 120 121 122 |
if (!fill) { inp += 4; size -= 4; } |
e76e1fdfa lib: add support ... |
123 124 125 126 |
if (posp) *posp += 4; continue; } |
4d4b866ae initrd: fix lz4 d... |
127 |
|
e76e1fdfa lib: add support ... |
128 129 130 |
if (posp) *posp += 4; |
4d4b866ae initrd: fix lz4 d... |
131 132 133 134 |
if (!fill) { inp += 4; size -= 4; } else { |
e76e1fdfa lib: add support ... |
135 136 137 138 |
if (chunksize > lz4_compressbound(uncomp_chunksize)) { error("chunk length is longer than allocated"); goto exit_2; } |
4d4b866ae initrd: fix lz4 d... |
139 140 141 142 143 |
size = fill(inp, chunksize); if (size < chunksize) { error("data corrupted"); goto exit_2; } |
e76e1fdfa lib: add support ... |
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
} #ifdef PREBOOT if (out_len >= uncomp_chunksize) { dest_len = uncomp_chunksize; out_len -= dest_len; } else dest_len = out_len; ret = lz4_decompress(inp, &chunksize, outp, dest_len); #else dest_len = uncomp_chunksize; ret = lz4_decompress_unknownoutputsize(inp, chunksize, outp, &dest_len); #endif if (ret < 0) { error("Decoding failed"); goto exit_2; } |
2a1d689c9 lib/decompress_un... |
161 |
ret = -1; |
e76e1fdfa lib: add support ... |
162 163 164 165 166 167 |
if (flush && flush(outp, dest_len) != dest_len) goto exit_2; if (output) outp += dest_len; if (posp) *posp += chunksize; |
4d4b866ae initrd: fix lz4 d... |
168 169 |
if (!fill) { size -= chunksize; |
e76e1fdfa lib: add support ... |
170 |
|
4d4b866ae initrd: fix lz4 d... |
171 172 173 174 175 176 177 |
if (size == 0) break; else if (size < 0) { error("data corrupted"); goto exit_2; } inp += chunksize; |
e76e1fdfa lib: add support ... |
178 |
} |
e76e1fdfa lib: add support ... |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
} ret = 0; exit_2: if (!input) large_free(inp_start); exit_1: if (!output) large_free(outp); exit_0: return ret; } #ifdef PREBOOT |
d97b07c54 initramfs: suppor... |
193 194 195 |
STATIC int INIT decompress(unsigned char *buf, long in_len, long (*fill)(void*, unsigned long), long (*flush)(void*, unsigned long), |
e76e1fdfa lib: add support ... |
196 |
unsigned char *output, |
d97b07c54 initramfs: suppor... |
197 |
long *posp, |
e76e1fdfa lib: add support ... |
198 199 200 201 202 203 |
void(*error)(char *x) ) { return unlz4(buf, in_len - 4, fill, flush, output, posp, error); } #endif |