~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/decompress_unlz4.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php