brintos

brintos / linux-shallow public Read only

0
0
Text · 4.0 KiB · 6c49481 Raw
197 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Squashfs - a compressed read only filesystem for Linux4 *5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 20106 * Phillip Lougher <phillip@squashfs.org.uk>7 *8 * xz_wrapper.c9 */10 11 12#include <linux/mutex.h>13#include <linux/bio.h>14#include <linux/slab.h>15#include <linux/xz.h>16#include <linux/bitops.h>17 18#include "squashfs_fs.h"19#include "squashfs_fs_sb.h"20#include "squashfs.h"21#include "decompressor.h"22#include "page_actor.h"23 24struct squashfs_xz {25	struct xz_dec *state;26	struct xz_buf buf;27};28 29struct disk_comp_opts {30	__le32 dictionary_size;31	__le32 flags;32};33 34struct comp_opts {35	int dict_size;36};37 38static void *squashfs_xz_comp_opts(struct squashfs_sb_info *msblk,39	void *buff, int len)40{41	struct disk_comp_opts *comp_opts = buff;42	struct comp_opts *opts;43	int err = 0, n;44 45	opts = kmalloc(sizeof(*opts), GFP_KERNEL);46	if (opts == NULL) {47		err = -ENOMEM;48		goto out2;49	}50 51	if (comp_opts) {52		/* check compressor options are the expected length */53		if (len < sizeof(*comp_opts)) {54			err = -EIO;55			goto out;56		}57 58		opts->dict_size = le32_to_cpu(comp_opts->dictionary_size);59 60		/* the dictionary size should be 2^n or 2^n+2^(n+1) */61		n = ffs(opts->dict_size) - 1;62		if (opts->dict_size != (1 << n) && opts->dict_size != (1 << n) +63						(1 << (n + 1))) {64			err = -EIO;65			goto out;66		}67	} else68		/* use defaults */69		opts->dict_size = max_t(int, msblk->block_size,70							SQUASHFS_METADATA_SIZE);71 72	return opts;73 74out:75	kfree(opts);76out2:77	return ERR_PTR(err);78}79 80 81static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff)82{83	struct comp_opts *comp_opts = buff;84	struct squashfs_xz *stream;85	int err;86 87	stream = kmalloc(sizeof(*stream), GFP_KERNEL);88	if (stream == NULL) {89		err = -ENOMEM;90		goto failed;91	}92 93	stream->state = xz_dec_init(XZ_PREALLOC, comp_opts->dict_size);94	if (stream->state == NULL) {95		kfree(stream);96		err = -ENOMEM;97		goto failed;98	}99 100	return stream;101 102failed:103	ERROR("Failed to initialise xz decompressor\n");104	return ERR_PTR(err);105}106 107 108static void squashfs_xz_free(void *strm)109{110	struct squashfs_xz *stream = strm;111 112	if (stream) {113		xz_dec_end(stream->state);114		kfree(stream);115	}116}117 118 119static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,120	struct bio *bio, int offset, int length,121	struct squashfs_page_actor *output)122{123	struct bvec_iter_all iter_all = {};124	struct bio_vec *bvec = bvec_init_iter_all(&iter_all);125	int total = 0, error = 0;126	struct squashfs_xz *stream = strm;127 128	xz_dec_reset(stream->state);129	stream->buf.in_pos = 0;130	stream->buf.in_size = 0;131	stream->buf.out_pos = 0;132	stream->buf.out_size = PAGE_SIZE;133	stream->buf.out = squashfs_first_page(output);134	if (IS_ERR(stream->buf.out)) {135		error = PTR_ERR(stream->buf.out);136		goto finish;137	}138 139	for (;;) {140		enum xz_ret xz_err;141 142		if (stream->buf.in_pos == stream->buf.in_size) {143			const void *data;144			int avail;145 146			if (!bio_next_segment(bio, &iter_all)) {147				/* XZ_STREAM_END must be reached. */148				error = -EIO;149				break;150			}151 152			avail = min(length, ((int)bvec->bv_len) - offset);153			data = bvec_virt(bvec);154			length -= avail;155			stream->buf.in = data + offset;156			stream->buf.in_size = avail;157			stream->buf.in_pos = 0;158			offset = 0;159		}160 161		if (stream->buf.out_pos == stream->buf.out_size) {162			stream->buf.out = squashfs_next_page(output);163			if (IS_ERR(stream->buf.out)) {164				error = PTR_ERR(stream->buf.out);165				break;166			} else if (stream->buf.out != NULL) {167				stream->buf.out_pos = 0;168				total += PAGE_SIZE;169			}170		}171 172		xz_err = xz_dec_run(stream->state, &stream->buf);173		if (xz_err == XZ_STREAM_END)174			break;175		if (xz_err != XZ_OK) {176			error = -EIO;177			break;178		}179	}180 181finish:182	squashfs_finish_page(output);183 184	return error ? error : total + stream->buf.out_pos;185}186 187const struct squashfs_decompressor squashfs_xz_comp_ops = {188	.init = squashfs_xz_init,189	.comp_opts = squashfs_xz_comp_opts,190	.free = squashfs_xz_free,191	.decompress = squashfs_xz_uncompress,192	.id = XZ_COMPRESSION,193	.name = "xz",194	.alloc_buffer = 1,195	.supported = 1196};197