vsprintf: Update %pI6c to not compress a single 0
[linux-2.6.git] / lib / decompress_unlzma.c
index 951f727..476c65a 100644 (file)
@@ -33,7 +33,6 @@
 #define PREBOOT
 #else
 #include <linux/decompress/unlzma.h>
-#include <linux/slab.h>
 #endif /* STATIC */
 
 #include <linux/decompress/mm.h>
@@ -74,6 +73,7 @@ struct rc {
        uint32_t code;
        uint32_t range;
        uint32_t bound;
+       void (*error)(char *);
 };
 
 
@@ -92,7 +92,7 @@ static void INIT rc_read(struct rc *rc)
 {
        rc->buffer_size = rc->fill((char *)rc->buffer, LZMA_IOBUF_SIZE);
        if (rc->buffer_size <= 0)
-               error("unexpected EOF");
+               rc->error("unexpected EOF");
        rc->ptr = rc->buffer;
        rc->buffer_end = rc->buffer + rc->buffer_size;
 }
@@ -127,12 +127,6 @@ static inline void INIT rc_init_code(struct rc *rc)
 }
 
 
-/* Called once. TODO: bb_maybe_free() */
-static inline void INIT rc_free(struct rc *rc)
-{
-       free(rc->buffer);
-}
-
 /* Called twice, but one callsite is in inline'd rc_is_bit_0_helper() */
 static void INIT rc_do_normalize(struct rc *rc)
 {
@@ -319,32 +313,38 @@ static inline uint8_t INIT peek_old_byte(struct writer *wr,
 
 }
 
-static inline void INIT write_byte(struct writer *wr, uint8_t byte)
+static inline int INIT write_byte(struct writer *wr, uint8_t byte)
 {
        wr->buffer[wr->buffer_pos++] = wr->previous_byte = byte;
        if (wr->flush && wr->buffer_pos == wr->header->dict_size) {
                wr->buffer_pos = 0;
                wr->global_pos += wr->header->dict_size;
-               wr->flush((char *)wr->buffer, wr->header->dict_size);
+               if (wr->flush((char *)wr->buffer, wr->header->dict_size)
+                               != wr->header->dict_size)
+                       return -1;
        }
+       return 0;
 }
 
 
-static inline void INIT copy_byte(struct writer *wr, uint32_t offs)
+static inline int INIT copy_byte(struct writer *wr, uint32_t offs)
 {
-       write_byte(wr, peek_old_byte(wr, offs));
+       return write_byte(wr, peek_old_byte(wr, offs));
 }
 
-static inline void INIT copy_bytes(struct writer *wr,
+static inline int INIT copy_bytes(struct writer *wr,
                                         uint32_t rep0, int len)
 {
        do {
-               copy_byte(wr, rep0);
+               if (copy_byte(wr, rep0))
+                       return -1;
                len--;
        } while (len != 0 && wr->buffer_pos < wr->header->dst_size);
+
+       return len;
 }
 
-static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
+static inline int INIT process_bit0(struct writer *wr, struct rc *rc,
                                     struct cstate *cst, uint16_t *p,
                                     int pos_state, uint16_t *prob,
                                     int lc, uint32_t literal_pos_mask) {
@@ -378,16 +378,17 @@ static inline void INIT process_bit0(struct writer *wr, struct rc *rc,
                uint16_t *prob_lit = prob + mi;
                rc_get_bit(rc, prob_lit, &mi);
        }
-       write_byte(wr, mi);
        if (cst->state < 4)
                cst->state = 0;
        else if (cst->state < 10)
                cst->state -= 3;
        else
                cst->state -= 6;
+
+       return write_byte(wr, mi);
 }
 
-static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
+static inline int INIT process_bit1(struct writer *wr, struct rc *rc,
                                            struct cstate *cst, uint16_t *p,
                                            int pos_state, uint16_t *prob) {
   int offset;
@@ -418,8 +419,7 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
 
                                cst->state = cst->state < LZMA_NUM_LIT_STATES ?
                                        9 : 11;
-                               copy_byte(wr, cst->rep0);
-                               return;
+                               return copy_byte(wr, cst->rep0);
                        } else {
                                rc_update_bit_1(rc, prob);
                        }
@@ -521,12 +521,15 @@ static inline void INIT process_bit1(struct writer *wr, struct rc *rc,
                } else
                        cst->rep0 = pos_slot;
                if (++(cst->rep0) == 0)
-                       return;
+                       return 0;
+               if (cst->rep0 > wr->header->dict_size
+                               || cst->rep0 > get_pos(wr))
+                       return -1;
        }
 
        len += LZMA_MATCH_MIN_LEN;
 
-       copy_bytes(wr, cst->rep0, len);
+       return copy_bytes(wr, cst->rep0, len);
 }
 
 
@@ -536,7 +539,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
                              int(*flush)(void*, unsigned int),
                              unsigned char *output,
                              int *posp,
-                             void(*error_fn)(char *x)
+                             void(*error)(char *x)
        )
 {
        struct lzma_header header;
@@ -552,7 +555,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
        unsigned char *inbuf;
        int ret = -1;
 
-       set_error_fn(error_fn);
+       rc.error = error;
 
        if (buf)
                inbuf = buf;
@@ -580,8 +583,10 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
                ((unsigned char *)&header)[i] = *rc.ptr++;
        }
 
-       if (header.pos >= (9 * 5 * 5))
+       if (header.pos >= (9 * 5 * 5)) {
                error("bad header");
+               goto exit_1;
+       }
 
        mi = 0;
        lc = header.pos;
@@ -627,21 +632,29 @@ STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
                int pos_state = get_pos(&wr) & pos_state_mask;
                uint16_t *prob = p + LZMA_IS_MATCH +
                        (cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state;
-               if (rc_is_bit_0(&rc, prob))
-                       process_bit0(&wr, &rc, &cst, p, pos_state, prob,
-                                    lc, literal_pos_mask);
-               else {
-                       process_bit1(&wr, &rc, &cst, p, pos_state, prob);
+               if (rc_is_bit_0(&rc, prob)) {
+                       if (process_bit0(&wr, &rc, &cst, p, pos_state, prob,
+                                       lc, literal_pos_mask)) {
+                               error("LZMA data is corrupt");
+                               goto exit_3;
+                       }
+               } else {
+                       if (process_bit1(&wr, &rc, &cst, p, pos_state, prob)) {
+                               error("LZMA data is corrupt");
+                               goto exit_3;
+                       }
                        if (cst.rep0 == 0)
                                break;
                }
+               if (rc.buffer_size <= 0)
+                       goto exit_3;
        }
 
        if (posp)
                *posp = rc.ptr-rc.buffer;
-       if (wr.flush)
-               wr.flush(wr.buffer, wr.buffer_pos);
-       ret = 0;
+       if (!wr.flush || wr.flush(wr.buffer, wr.buffer_pos) == wr.buffer_pos)
+               ret = 0;
+exit_3:
        large_free(p);
 exit_2:
        if (!output)
@@ -659,9 +672,9 @@ STATIC int INIT decompress(unsigned char *buf, int in_len,
                              int(*flush)(void*, unsigned int),
                              unsigned char *output,
                              int *posp,
-                             void(*error_fn)(char *x)
+                             void(*error)(char *x)
        )
 {
-       return unlzma(buf, in_len - 4, fill, flush, output, posp, error_fn);
+       return unlzma(buf, in_len - 4, fill, flush, output, posp, error);
 }
 #endif