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