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"
22 lizard_alloc_internal(struct lizard_buffer *buf, uns max_len)
30 buf->len = ALIGN(max_len + 3, PAGE_SIZE); // +3 due to the unaligned access
31 buf->start = mmap(NULL, buf->len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
32 if (buf->start == MAP_FAILED)
33 die("mmap(anonymous): %m");
34 if (mprotect(buf->start + buf->len, PAGE_SIZE, PROT_NONE) < 0)
38 struct lizard_buffer *
39 lizard_alloc(uns max_len)
41 struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
42 lizard_alloc_internal(buf, max_len);
43 buf->old_sigsegv_handler = xmalloc(sizeof(struct sigaction));
44 handle_signal(SIGSEGV, buf->old_sigsegv_handler);
49 lizard_free(struct lizard_buffer *buf)
52 munmap(buf->start, buf->len + PAGE_SIZE);
53 unhandle_signal(SIGSEGV, buf->old_sigsegv_handler);
54 xfree(buf->old_sigsegv_handler);
59 lizard_realloc(struct lizard_buffer *buf, uns max_len)
62 if (max_len <= buf->len)
64 if (max_len < 2*buf->len) // to ensure amortized logarithmic complexity
67 munmap(buf->start - 3, buf->len + PAGE_SIZE);
68 lizard_alloc_internal(buf, max_len);
71 static jmp_buf safe_decompress_jump;
73 sigsegv_handler(int signal UNUSED)
75 log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
76 longjmp(safe_decompress_jump, 1);
81 lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length)
82 /* Decompresses into buf->ptr and returns the length of the uncompressed
83 * file. If an error has occured, -1 is returned and errno is set. SIGSEGV
84 * is caught in the case of buffer-overflow. The function is not re-entrant
85 * because of a static longjmp handler. */
87 uns lock_offset = ALIGN(expected_length + 3, PAGE_SIZE); // +3 due to the unaligned access
88 if (lock_offset > buf->len)
93 volatile sh_sighandler_t old_handler = signal_handler[SIGSEGV];
94 signal_handler[SIGSEGV] = sigsegv_handler;
96 if (!setjmp(safe_decompress_jump))
98 buf->ptr = buf->start + buf->len - lock_offset;
99 len = lizard_decompress(in, buf->ptr);
107 signal_handler[SIGSEGV] = old_handler;