2 * LiZaRd -- Fast compression method based on Lempel-Ziv 77
4 * (c) 2004, Robert Spalek <robert@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
11 #include "lib/lizard.h"
21 struct lizard_buffer {
24 struct sigaction *old_sigsegv_handler;
27 struct lizard_buffer *
30 struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
33 buf->old_sigsegv_handler = xmalloc(sizeof(struct sigaction));
34 handle_signal(SIGSEGV, buf->old_sigsegv_handler);
39 lizard_free(struct lizard_buffer *buf)
42 munmap(buf->ptr, buf->len + PAGE_SIZE);
43 unhandle_signal(SIGSEGV, buf->old_sigsegv_handler);
44 xfree(buf->old_sigsegv_handler);
49 lizard_realloc(struct lizard_buffer *buf, uns max_len)
50 /* max_len needs to be aligned to PAGE_SIZE */
52 if (max_len <= buf->len)
54 if (max_len < 2*buf->len) // to ensure logarithmic cost
58 munmap(buf->ptr, buf->len + PAGE_SIZE);
60 buf->ptr = mmap(NULL, buf->len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
61 if (buf->ptr == MAP_FAILED)
62 die("mmap(anonymous): %m");
63 if (mprotect(buf->ptr + buf->len, PAGE_SIZE, PROT_NONE) < 0)
67 static jmp_buf safe_decompress_jump;
69 sigsegv_handler(int signal UNUSED)
71 log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
72 longjmp(safe_decompress_jump, 1);
77 lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length, byte **ptr)
78 /* Decompresses in into buf, sets *ptr to the data, and returns the
79 * uncompressed length. If an error has occured, -1 is returned and errno is
80 * set. The buffer buf is automatically reallocated. SIGSEGV is caught in
81 * case of buffer-overflow. The function is not re-entrant because of a
82 * static longjmp handler. */
84 uns lock_offset = ALIGN(expected_length + 3, PAGE_SIZE); // +3 due to the unaligned access
85 if (lock_offset > buf->len)
86 lizard_realloc(buf, lock_offset);
87 volatile sh_sighandler_t old_handler = signal_handler[SIGSEGV];
88 signal_handler[SIGSEGV] = sigsegv_handler;
90 if (!setjmp(safe_decompress_jump))
92 *ptr = buf->ptr + buf->len - lock_offset;
93 len = lizard_decompress(in, *ptr);
101 signal_handler[SIGSEGV] = old_handler;