Path: blob/main/sys/contrib/xz-embedded/linux/lib/xz/xz_dec_test.c
48521 views
/*1* XZ decoder tester2*3* Author: Lasse Collin <[email protected]>4*5* This file has been put into the public domain.6* You can do whatever you want with this file.7*/89#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/fs.h>12#include <linux/uaccess.h>13#include <linux/crc32.h>14#include <linux/xz.h>1516/* Maximum supported dictionary size */17#define DICT_MAX (1 << 20)1819/* Device name to pass to register_chrdev(). */20#define DEVICE_NAME "xz_dec_test"2122/* Dynamically allocated device major number */23static int device_major;2425/*26* We reuse the same decoder state, and thus can decode only one27* file at a time.28*/29static bool device_is_open;3031/* XZ decoder state */32static struct xz_dec *state;3334/*35* Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after36* it has returned XZ_STREAM_END, so we make this static.37*/38static enum xz_ret ret;3940/*41* Input and output buffers. The input buffer is used as a temporary safe42* place for the data coming from the userspace.43*/44static uint8_t buffer_in[1024];45static uint8_t buffer_out[1024];4647/*48* Structure to pass the input and output buffers to the XZ decoder.49* A few of the fields are never modified so we initialize them here.50*/51static struct xz_buf buffers = {52.in = buffer_in,53.out = buffer_out,54.out_size = sizeof(buffer_out)55};5657/*58* CRC32 of uncompressed data. This is used to give the user a simple way59* to check that the decoder produces correct output.60*/61static uint32_t crc;6263static int xz_dec_test_open(struct inode *i, struct file *f)64{65if (device_is_open)66return -EBUSY;6768device_is_open = true;6970xz_dec_reset(state);71ret = XZ_OK;72crc = 0xFFFFFFFF;7374buffers.in_pos = 0;75buffers.in_size = 0;76buffers.out_pos = 0;7778printk(KERN_INFO DEVICE_NAME ": opened\n");79return 0;80}8182static int xz_dec_test_release(struct inode *i, struct file *f)83{84device_is_open = false;8586if (ret == XZ_OK)87printk(KERN_INFO DEVICE_NAME ": input was truncated\n");8889printk(KERN_INFO DEVICE_NAME ": closed\n");90return 0;91}9293/*94* Decode the data given to us from the userspace. CRC32 of the uncompressed95* data is calculated and is printed at the end of successful decoding. The96* uncompressed data isn't stored anywhere for further use.97*98* The .xz file must have exactly one Stream and no Stream Padding. The data99* after the first Stream is considered to be garbage.100*/101static ssize_t xz_dec_test_write(struct file *file, const char __user *buf,102size_t size, loff_t *pos)103{104size_t remaining;105106if (ret != XZ_OK) {107if (size > 0)108printk(KERN_INFO DEVICE_NAME ": %zu bytes of "109"garbage at the end of the file\n",110size);111112return -ENOSPC;113}114115printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",116size);117118remaining = size;119while ((remaining > 0 || buffers.out_pos == buffers.out_size)120&& ret == XZ_OK) {121if (buffers.in_pos == buffers.in_size) {122buffers.in_pos = 0;123buffers.in_size = min(remaining, sizeof(buffer_in));124if (copy_from_user(buffer_in, buf, buffers.in_size))125return -EFAULT;126127buf += buffers.in_size;128remaining -= buffers.in_size;129}130131buffers.out_pos = 0;132ret = xz_dec_run(state, &buffers);133crc = crc32(crc, buffer_out, buffers.out_pos);134}135136switch (ret) {137case XZ_OK:138printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");139return size;140141case XZ_STREAM_END:142printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "143"CRC32 = 0x%08X\n", ~crc);144return size - remaining - (buffers.in_size - buffers.in_pos);145146case XZ_MEMLIMIT_ERROR:147printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");148break;149150case XZ_FORMAT_ERROR:151printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");152break;153154case XZ_OPTIONS_ERROR:155printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");156break;157158case XZ_DATA_ERROR:159printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");160break;161162case XZ_BUF_ERROR:163printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");164break;165166default:167printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");168break;169}170171return -EIO;172}173174/* Allocate the XZ decoder state and register the character device. */175static int __init xz_dec_test_init(void)176{177static const struct file_operations fileops = {178.owner = THIS_MODULE,179.open = &xz_dec_test_open,180.release = &xz_dec_test_release,181.write = &xz_dec_test_write182};183184state = xz_dec_init(XZ_PREALLOC, DICT_MAX);185if (state == NULL)186return -ENOMEM;187188device_major = register_chrdev(0, DEVICE_NAME, &fileops);189if (device_major < 0) {190xz_dec_end(state);191return device_major;192}193194printk(KERN_INFO DEVICE_NAME ": module loaded\n");195printk(KERN_INFO DEVICE_NAME ": Create a device node with "196"'mknod " DEVICE_NAME " c %d 0' and write .xz files "197"to it.\n", device_major);198return 0;199}200201static void __exit xz_dec_test_exit(void)202{203unregister_chrdev(device_major, DEVICE_NAME);204xz_dec_end(state);205printk(KERN_INFO DEVICE_NAME ": module unloaded\n");206}207208module_init(xz_dec_test_init);209module_exit(xz_dec_test_exit);210211MODULE_DESCRIPTION("XZ decompressor tester");212MODULE_VERSION("1.0");213MODULE_AUTHOR("Lasse Collin <[email protected]>");214215/*216* This code is in the public domain, but in Linux it's simplest to just217* say it's GPL and consider the authors as the copyright holders.218*/219MODULE_LICENSE("GPL");220221222