root/lib/xz/xz_dec_test.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xz_dec_test_open
  2. xz_dec_test_release
  3. xz_dec_test_write
  4. xz_dec_test_init
  5. xz_dec_test_exit

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

/* [<][>][^][v][top][bottom][index][help] */