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 *
22 lizard_alloc(uns max_len)
24 static byte *zero = "/dev/zero";
25 int fd = open(zero, O_RDWR);
27 die("open(%s): %m", zero);
28 struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
29 buf->len = ALIGN(max_len + PAGE_SIZE, PAGE_SIZE);
30 buf->ptr = mmap(NULL, buf->len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
31 if (buf->ptr == MAP_FAILED)
32 die("mmap(%s): %m", zero);
37 lizard_free(struct lizard_buffer *buf)
39 munmap(buf->ptr, buf->len);
43 static jmp_buf safe_decompress_jump;
45 sigsegv_handler(int UNUSED whatsit)
47 log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
48 longjmp(safe_decompress_jump, 1);
52 lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length)
53 /* Decompresses into buf->ptr and returns the length of the uncompressed
54 * file. If an error has occured, -1 is returned and errno is set. SIGSEGV
55 * is caught in the case of buffer-overflow. The function is not re-entrant
56 * because of a static longjmp handler. */
58 uns lock_offset = ALIGN(expected_length, PAGE_SIZE);
59 if (lock_offset + PAGE_SIZE > buf->len)
64 mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_NONE);
65 volatile sighandler_t old_handler = signal(SIGSEGV, sigsegv_handler);
67 if (!setjmp(safe_decompress_jump))
69 len = lizard_decompress(in, buf->ptr);
77 signal(SIGSEGV, old_handler);
78 mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_READ | PROT_WRITE);