Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * XZ decoder tester
0003  *
0004  * Author: Lasse Collin <lasse.collin@tukaani.org>
0005  *
0006  * This file has been put into the public domain.
0007  * You can do whatever you want with this file.
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/fs.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/crc32.h>
0015 #include <linux/xz.h>
0016 
0017 /* Maximum supported dictionary size */
0018 #define DICT_MAX (1 << 20)
0019 
0020 /* Device name to pass to register_chrdev(). */
0021 #define DEVICE_NAME "xz_dec_test"
0022 
0023 /* Dynamically allocated device major number */
0024 static int device_major;
0025 
0026 /*
0027  * We reuse the same decoder state, and thus can decode only one
0028  * file at a time.
0029  */
0030 static bool device_is_open;
0031 
0032 /* XZ decoder state */
0033 static struct xz_dec *state;
0034 
0035 /*
0036  * Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after
0037  * it has returned XZ_STREAM_END, so we make this static.
0038  */
0039 static enum xz_ret ret;
0040 
0041 /*
0042  * Input and output buffers. The input buffer is used as a temporary safe
0043  * place for the data coming from the userspace.
0044  */
0045 static uint8_t buffer_in[1024];
0046 static uint8_t buffer_out[1024];
0047 
0048 /*
0049  * Structure to pass the input and output buffers to the XZ decoder.
0050  * A few of the fields are never modified so we initialize them here.
0051  */
0052 static struct xz_buf buffers = {
0053     .in = buffer_in,
0054     .out = buffer_out,
0055     .out_size = sizeof(buffer_out)
0056 };
0057 
0058 /*
0059  * CRC32 of uncompressed data. This is used to give the user a simple way
0060  * to check that the decoder produces correct output.
0061  */
0062 static uint32_t crc;
0063 
0064 static int xz_dec_test_open(struct inode *i, struct file *f)
0065 {
0066     if (device_is_open)
0067         return -EBUSY;
0068 
0069     device_is_open = true;
0070 
0071     xz_dec_reset(state);
0072     ret = XZ_OK;
0073     crc = 0xFFFFFFFF;
0074 
0075     buffers.in_pos = 0;
0076     buffers.in_size = 0;
0077     buffers.out_pos = 0;
0078 
0079     printk(KERN_INFO DEVICE_NAME ": opened\n");
0080     return 0;
0081 }
0082 
0083 static int xz_dec_test_release(struct inode *i, struct file *f)
0084 {
0085     device_is_open = false;
0086 
0087     if (ret == XZ_OK)
0088         printk(KERN_INFO DEVICE_NAME ": input was truncated\n");
0089 
0090     printk(KERN_INFO DEVICE_NAME ": closed\n");
0091     return 0;
0092 }
0093 
0094 /*
0095  * Decode the data given to us from the userspace. CRC32 of the uncompressed
0096  * data is calculated and is printed at the end of successful decoding. The
0097  * uncompressed data isn't stored anywhere for further use.
0098  *
0099  * The .xz file must have exactly one Stream and no Stream Padding. The data
0100  * after the first Stream is considered to be garbage.
0101  */
0102 static ssize_t xz_dec_test_write(struct file *file, const char __user *buf,
0103                  size_t size, loff_t *pos)
0104 {
0105     size_t remaining;
0106 
0107     if (ret != XZ_OK) {
0108         if (size > 0)
0109             printk(KERN_INFO DEVICE_NAME ": %zu bytes of "
0110                     "garbage at the end of the file\n",
0111                     size);
0112 
0113         return -ENOSPC;
0114     }
0115 
0116     printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",
0117             size);
0118 
0119     remaining = size;
0120     while ((remaining > 0 || buffers.out_pos == buffers.out_size)
0121             && ret == XZ_OK) {
0122         if (buffers.in_pos == buffers.in_size) {
0123             buffers.in_pos = 0;
0124             buffers.in_size = min(remaining, sizeof(buffer_in));
0125             if (copy_from_user(buffer_in, buf, buffers.in_size))
0126                 return -EFAULT;
0127 
0128             buf += buffers.in_size;
0129             remaining -= buffers.in_size;
0130         }
0131 
0132         buffers.out_pos = 0;
0133         ret = xz_dec_run(state, &buffers);
0134         crc = crc32(crc, buffer_out, buffers.out_pos);
0135     }
0136 
0137     switch (ret) {
0138     case XZ_OK:
0139         printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");
0140         return size;
0141 
0142     case XZ_STREAM_END:
0143         printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "
0144                 "CRC32 = 0x%08X\n", ~crc);
0145         return size - remaining - (buffers.in_size - buffers.in_pos);
0146 
0147     case XZ_MEMLIMIT_ERROR:
0148         printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");
0149         break;
0150 
0151     case XZ_FORMAT_ERROR:
0152         printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");
0153         break;
0154 
0155     case XZ_OPTIONS_ERROR:
0156         printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");
0157         break;
0158 
0159     case XZ_DATA_ERROR:
0160         printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");
0161         break;
0162 
0163     case XZ_BUF_ERROR:
0164         printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");
0165         break;
0166 
0167     default:
0168         printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");
0169         break;
0170     }
0171 
0172     return -EIO;
0173 }
0174 
0175 /* Allocate the XZ decoder state and register the character device. */
0176 static int __init xz_dec_test_init(void)
0177 {
0178     static const struct file_operations fileops = {
0179         .owner = THIS_MODULE,
0180         .open = &xz_dec_test_open,
0181         .release = &xz_dec_test_release,
0182         .write = &xz_dec_test_write
0183     };
0184 
0185     state = xz_dec_init(XZ_PREALLOC, DICT_MAX);
0186     if (state == NULL)
0187         return -ENOMEM;
0188 
0189     device_major = register_chrdev(0, DEVICE_NAME, &fileops);
0190     if (device_major < 0) {
0191         xz_dec_end(state);
0192         return device_major;
0193     }
0194 
0195     printk(KERN_INFO DEVICE_NAME ": module loaded\n");
0196     printk(KERN_INFO DEVICE_NAME ": Create a device node with "
0197             "'mknod " DEVICE_NAME " c %d 0' and write .xz files "
0198             "to it.\n", device_major);
0199     return 0;
0200 }
0201 
0202 static void __exit xz_dec_test_exit(void)
0203 {
0204     unregister_chrdev(device_major, DEVICE_NAME);
0205     xz_dec_end(state);
0206     printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
0207 }
0208 
0209 module_init(xz_dec_test_init);
0210 module_exit(xz_dec_test_exit);
0211 
0212 MODULE_DESCRIPTION("XZ decompressor tester");
0213 MODULE_VERSION("1.0");
0214 MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org>");
0215 
0216 /*
0217  * This code is in the public domain, but in Linux it's simplest to just
0218  * say it's GPL and consider the authors as the copyright holders.
0219  */
0220 MODULE_LICENSE("GPL");