^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * XZ decoder tester
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Lasse Collin <lasse.collin@tukaani.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file has been put into the public domain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * You can do whatever you want with this file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/crc32.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/xz.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /* Maximum supported dictionary size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define DICT_MAX (1 << 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Device name to pass to register_chrdev(). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define DEVICE_NAME "xz_dec_test"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /* Dynamically allocated device major number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static int device_major;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * We reuse the same decoder state, and thus can decode only one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * file at a time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static bool device_is_open;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* XZ decoder state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static struct xz_dec *state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * it has returned XZ_STREAM_END, so we make this static.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static enum xz_ret ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Input and output buffers. The input buffer is used as a temporary safe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * place for the data coming from the userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static uint8_t buffer_in[1024];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static uint8_t buffer_out[1024];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * Structure to pass the input and output buffers to the XZ decoder.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * A few of the fields are never modified so we initialize them here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static struct xz_buf buffers = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) .in = buffer_in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .out = buffer_out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .out_size = sizeof(buffer_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * CRC32 of uncompressed data. This is used to give the user a simple way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * to check that the decoder produces correct output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static uint32_t crc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int xz_dec_test_open(struct inode *i, struct file *f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (device_is_open)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) device_is_open = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) xz_dec_reset(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ret = XZ_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) crc = 0xFFFFFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) buffers.in_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) buffers.in_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) buffers.out_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) printk(KERN_INFO DEVICE_NAME ": opened\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int xz_dec_test_release(struct inode *i, struct file *f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) device_is_open = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (ret == XZ_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) printk(KERN_INFO DEVICE_NAME ": input was truncated\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) printk(KERN_INFO DEVICE_NAME ": closed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * Decode the data given to us from the userspace. CRC32 of the uncompressed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * data is calculated and is printed at the end of successful decoding. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * uncompressed data isn't stored anywhere for further use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * The .xz file must have exactly one Stream and no Stream Padding. The data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * after the first Stream is considered to be garbage.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static ssize_t xz_dec_test_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) size_t size, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) size_t remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (ret != XZ_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (size > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) printk(KERN_INFO DEVICE_NAME ": %zu bytes of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) "garbage at the end of the file\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) remaining = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) while ((remaining > 0 || buffers.out_pos == buffers.out_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) && ret == XZ_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (buffers.in_pos == buffers.in_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) buffers.in_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) buffers.in_size = min(remaining, sizeof(buffer_in));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (copy_from_user(buffer_in, buf, buffers.in_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) buf += buffers.in_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) remaining -= buffers.in_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) buffers.out_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) ret = xz_dec_run(state, &buffers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) crc = crc32(crc, buffer_out, buffers.out_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) switch (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) case XZ_OK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) case XZ_STREAM_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) "CRC32 = 0x%08X\n", ~crc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return size - remaining - (buffers.in_size - buffers.in_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) case XZ_MEMLIMIT_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) case XZ_FORMAT_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case XZ_OPTIONS_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case XZ_DATA_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case XZ_BUF_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Allocate the XZ decoder state and register the character device. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static int __init xz_dec_test_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static const struct file_operations fileops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .open = &xz_dec_test_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .release = &xz_dec_test_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .write = &xz_dec_test_write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) state = xz_dec_init(XZ_PREALLOC, DICT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (state == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) device_major = register_chrdev(0, DEVICE_NAME, &fileops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (device_major < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) xz_dec_end(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return device_major;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) printk(KERN_INFO DEVICE_NAME ": module loaded\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) printk(KERN_INFO DEVICE_NAME ": Create a device node with "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) "'mknod " DEVICE_NAME " c %d 0' and write .xz files "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) "to it.\n", device_major);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static void __exit xz_dec_test_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unregister_chrdev(device_major, DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) xz_dec_end(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) module_init(xz_dec_test_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) module_exit(xz_dec_test_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) MODULE_DESCRIPTION("XZ decompressor tester");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) MODULE_VERSION("1.0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * This code is in the public domain, but in Linux it's simplest to just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * say it's GPL and consider the authors as the copyright holders.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) MODULE_LICENSE("GPL");