brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · 53d3600 Raw
215 lines · c
1// SPDX-License-Identifier: 0BSD2 3/*4 * XZ decoder tester5 *6 * Author: Lasse Collin <lasse.collin@tukaani.org>7 */8 9#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>15 16/* Maximum supported dictionary size */17#define DICT_MAX (1 << 20)18 19/* Device name to pass to register_chrdev(). */20#define DEVICE_NAME "xz_dec_test"21 22/* Dynamically allocated device major number */23static int device_major;24 25/*26 * We reuse the same decoder state, and thus can decode only one27 * file at a time.28 */29static bool device_is_open;30 31/* XZ decoder state */32static struct xz_dec *state;33 34/*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;39 40/*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];46 47/*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};56 57/*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;62 63static int xz_dec_test_open(struct inode *i, struct file *f)64{65	if (device_is_open)66		return -EBUSY;67 68	device_is_open = true;69 70	xz_dec_reset(state);71	ret = XZ_OK;72	crc = 0xFFFFFFFF;73 74	buffers.in_pos = 0;75	buffers.in_size = 0;76	buffers.out_pos = 0;77 78	printk(KERN_INFO DEVICE_NAME ": opened\n");79	return 0;80}81 82static int xz_dec_test_release(struct inode *i, struct file *f)83{84	device_is_open = false;85 86	if (ret == XZ_OK)87		printk(KERN_INFO DEVICE_NAME ": input was truncated\n");88 89	printk(KERN_INFO DEVICE_NAME ": closed\n");90	return 0;91}92 93/*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,102				 size_t size, loff_t *pos)103{104	size_t remaining;105 106	if (ret != XZ_OK) {107		if (size > 0)108			printk(KERN_INFO DEVICE_NAME ": %zu bytes of "109					"garbage at the end of the file\n",110					size);111 112		return -ENOSPC;113	}114 115	printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",116			size);117 118	remaining = size;119	while ((remaining > 0 || buffers.out_pos == buffers.out_size)120			&& ret == XZ_OK) {121		if (buffers.in_pos == buffers.in_size) {122			buffers.in_pos = 0;123			buffers.in_size = min(remaining, sizeof(buffer_in));124			if (copy_from_user(buffer_in, buf, buffers.in_size))125				return -EFAULT;126 127			buf += buffers.in_size;128			remaining -= buffers.in_size;129		}130 131		buffers.out_pos = 0;132		ret = xz_dec_run(state, &buffers);133		crc = crc32(crc, buffer_out, buffers.out_pos);134	}135 136	switch (ret) {137	case XZ_OK:138		printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");139		return size;140 141	case XZ_STREAM_END:142		printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "143				"CRC32 = 0x%08X\n", ~crc);144		return size - remaining - (buffers.in_size - buffers.in_pos);145 146	case XZ_MEMLIMIT_ERROR:147		printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");148		break;149 150	case XZ_FORMAT_ERROR:151		printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");152		break;153 154	case XZ_OPTIONS_ERROR:155		printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");156		break;157 158	case XZ_DATA_ERROR:159		printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");160		break;161 162	case XZ_BUF_ERROR:163		printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");164		break;165 166	default:167		printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");168		break;169	}170 171	return -EIO;172}173 174/* Allocate the XZ decoder state and register the character device. */175static int __init xz_dec_test_init(void)176{177	static 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	};183 184	state = xz_dec_init(XZ_PREALLOC, DICT_MAX);185	if (state == NULL)186		return -ENOMEM;187 188	device_major = register_chrdev(0, DEVICE_NAME, &fileops);189	if (device_major < 0) {190		xz_dec_end(state);191		return device_major;192	}193 194	printk(KERN_INFO DEVICE_NAME ": module loaded\n");195	printk(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);198	return 0;199}200 201static void __exit xz_dec_test_exit(void)202{203	unregister_chrdev(device_major, DEVICE_NAME);204	xz_dec_end(state);205	printk(KERN_INFO DEVICE_NAME ": module unloaded\n");206}207 208module_init(xz_dec_test_init);209module_exit(xz_dec_test_exit);210 211MODULE_DESCRIPTION("XZ decompressor tester");212MODULE_VERSION("1.0");213MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org>");214MODULE_LICENSE("Dual BSD/GPL");215