Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Squashfs - a compressed read only filesystem for Linux
0004  *
0005  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
0006  * Phillip Lougher <phillip@squashfs.org.uk>
0007  *
0008  * zlib_wrapper.c
0009  */
0010 
0011 
0012 #include <linux/mutex.h>
0013 #include <linux/bio.h>
0014 #include <linux/slab.h>
0015 #include <linux/zlib.h>
0016 #include <linux/vmalloc.h>
0017 
0018 #include "squashfs_fs.h"
0019 #include "squashfs_fs_sb.h"
0020 #include "squashfs.h"
0021 #include "decompressor.h"
0022 #include "page_actor.h"
0023 
0024 static void *zlib_init(struct squashfs_sb_info *dummy, void *buff)
0025 {
0026     z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
0027     if (stream == NULL)
0028         goto failed;
0029     stream->workspace = vmalloc(zlib_inflate_workspacesize());
0030     if (stream->workspace == NULL)
0031         goto failed;
0032 
0033     return stream;
0034 
0035 failed:
0036     ERROR("Failed to allocate zlib workspace\n");
0037     kfree(stream);
0038     return ERR_PTR(-ENOMEM);
0039 }
0040 
0041 
0042 static void zlib_free(void *strm)
0043 {
0044     z_stream *stream = strm;
0045 
0046     if (stream)
0047         vfree(stream->workspace);
0048     kfree(stream);
0049 }
0050 
0051 
0052 static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
0053     struct bio *bio, int offset, int length,
0054     struct squashfs_page_actor *output)
0055 {
0056     struct bvec_iter_all iter_all = {};
0057     struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
0058     int zlib_init = 0, error = 0;
0059     z_stream *stream = strm;
0060 
0061     stream->avail_out = PAGE_SIZE;
0062     stream->next_out = squashfs_first_page(output);
0063     stream->avail_in = 0;
0064 
0065     if (IS_ERR(stream->next_out)) {
0066         error = PTR_ERR(stream->next_out);
0067         goto finish;
0068     }
0069 
0070     for (;;) {
0071         int zlib_err;
0072 
0073         if (stream->avail_in == 0) {
0074             const void *data;
0075             int avail;
0076 
0077             if (!bio_next_segment(bio, &iter_all)) {
0078                 /* Z_STREAM_END must be reached. */
0079                 error = -EIO;
0080                 break;
0081             }
0082 
0083             avail = min(length, ((int)bvec->bv_len) - offset);
0084             data = bvec_virt(bvec);
0085             length -= avail;
0086             stream->next_in = data + offset;
0087             stream->avail_in = avail;
0088             offset = 0;
0089         }
0090 
0091         if (stream->avail_out == 0) {
0092             stream->next_out = squashfs_next_page(output);
0093             if (IS_ERR(stream->next_out)) {
0094                 error = PTR_ERR(stream->next_out);
0095                 break;
0096             } else if (stream->next_out != NULL)
0097                 stream->avail_out = PAGE_SIZE;
0098         }
0099 
0100         if (!zlib_init) {
0101             zlib_err = zlib_inflateInit(stream);
0102             if (zlib_err != Z_OK) {
0103                 error = -EIO;
0104                 break;
0105             }
0106             zlib_init = 1;
0107         }
0108 
0109         zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
0110         if (zlib_err == Z_STREAM_END)
0111             break;
0112         if (zlib_err != Z_OK) {
0113             error = -EIO;
0114             break;
0115         }
0116     }
0117 
0118 finish:
0119     squashfs_finish_page(output);
0120 
0121     if (!error)
0122         if (zlib_inflateEnd(stream) != Z_OK)
0123             error = -EIO;
0124 
0125     return error ? error : stream->total_out;
0126 }
0127 
0128 const struct squashfs_decompressor squashfs_zlib_comp_ops = {
0129     .init = zlib_init,
0130     .free = zlib_free,
0131     .decompress = zlib_uncompress,
0132     .id = ZLIB_COMPRESSION,
0133     .name = "zlib",
0134     .alloc_buffer = 1,
0135     .supported = 1
0136 };
0137