• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/fs/squashfs/
1/* Modified by Broadcom Corp. Portions Copyright (c) Broadcom Corp, 2012. */
2/*
3 * Squashfs - a compressed read only filesystem for Linux
4 *
5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
6 * Phillip Lougher <phillip@lougher.demon.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 * xz_wrapper.c
23 */
24
25
26#include <linux/mutex.h>
27#include <linux/buffer_head.h>
28#include <linux/slab.h>
29#include <linux/xz.h>
30#include <linux/bitops.h>
31
32#include "squashfs_fs.h"
33#include "squashfs_fs_sb.h"
34#include "squashfs.h"
35#include "decompressor.h"
36
37struct squashfs_xz {
38	struct xz_dec *state;
39	struct xz_buf buf;
40};
41
42struct comp_opts {
43	__le32 dictionary_size;
44	__le32 flags;
45};
46
47static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff,
48	int len)
49{
50	struct comp_opts *comp_opts = buff;
51	struct squashfs_xz *stream;
52	int dict_size = msblk->block_size;
53	int err, n;
54
55	if (comp_opts) {
56		/* check compressor options are the expected length */
57		if (len < sizeof(*comp_opts)) {
58			err = -EIO;
59			ERROR("squashfs_xz_init:1:: len=%d < %d \n", len, sizeof(*comp_opts));
60			goto failed;
61		}
62
63		dict_size = le32_to_cpu(comp_opts->dictionary_size);
64
65		/* the dictionary size should be 2^n or 2^n+2^(n+1) */
66		n = ffs(dict_size) - 1;
67		if (dict_size != (1 << n) && dict_size != (1 << n) +
68						(1 << (n + 1))) {
69			ERROR("squashfs_xz_init:2:: n =%d /dict_size %d/comp_opts->dictionary_size %d \n",
70				n, dict_size,comp_opts->dictionary_size);
71			err = -EIO;
72			goto failed;
73		}
74	}
75
76	dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE);
77
78	stream = kmalloc(sizeof(*stream), GFP_KERNEL);
79	if (stream == NULL) {
80		ERROR("squashfs_xz_init:3");
81		err = -ENOMEM;
82		goto failed;
83	}
84
85	stream->state = xz_dec_init(XZ_PREALLOC, dict_size);
86	if (stream->state == NULL) {
87		kfree(stream);
88		ERROR("squashfs_xz_init:4");
89		err = -ENOMEM;
90		goto failed;
91	}
92
93	return stream;
94
95failed:
96	ERROR("Failed to initialise xz decompressor\n");
97	return ERR_PTR(err);
98}
99
100
101static void squashfs_xz_free(void *strm)
102{
103	struct squashfs_xz *stream = strm;
104
105	if (stream) {
106		xz_dec_end(stream->state);
107		kfree(stream);
108	}
109}
110
111
112static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
113	struct buffer_head **bh, int b, int offset, int length, int srclength,
114	int pages)
115{
116	enum xz_ret xz_err;
117	int avail, total = 0, k = 0, page = 0;
118	struct squashfs_xz *stream = msblk->stream;
119
120	mutex_lock(&msblk->read_data_mutex);
121
122	xz_dec_reset(stream->state);
123	stream->buf.in_pos = 0;
124	stream->buf.in_size = 0;
125	stream->buf.out_pos = 0;
126	stream->buf.out_size = PAGE_CACHE_SIZE;
127	stream->buf.out = buffer[page++];
128
129	do {
130		if (stream->buf.in_pos == stream->buf.in_size && k < b) {
131			avail = min(length, msblk->devblksize - offset);
132			length -= avail;
133			wait_on_buffer(bh[k]);
134			if (!buffer_uptodate(bh[k]))
135				goto release_mutex;
136
137			stream->buf.in = bh[k]->b_data + offset;
138			stream->buf.in_size = avail;
139			stream->buf.in_pos = 0;
140			offset = 0;
141		}
142
143		if (stream->buf.out_pos == stream->buf.out_size
144							&& page < pages) {
145			stream->buf.out = buffer[page++];
146			stream->buf.out_pos = 0;
147			total += PAGE_CACHE_SIZE;
148		}
149
150		xz_err = xz_dec_run(stream->state, &stream->buf);
151
152		if (stream->buf.in_pos == stream->buf.in_size && k < b)
153			put_bh(bh[k++]);
154	} while (xz_err == XZ_OK);
155
156	if (xz_err != XZ_STREAM_END) {
157		ERROR("xz_dec_run error, data probably corrupt\n");
158		goto release_mutex;
159	}
160
161	if (k < b) {
162		ERROR("xz_uncompress error, input remaining\n");
163		goto release_mutex;
164	}
165
166	total += stream->buf.out_pos;
167	mutex_unlock(&msblk->read_data_mutex);
168	return total;
169
170release_mutex:
171	mutex_unlock(&msblk->read_data_mutex);
172
173	for (; k < b; k++)
174		put_bh(bh[k]);
175
176	return -EIO;
177}
178
179const struct squashfs_decompressor squashfs_xz_comp_ops = {
180	.init = squashfs_xz_init,
181	.free = squashfs_xz_free,
182	.decompress = squashfs_xz_uncompress,
183	.id = XZ_COMPRESSION,
184	.name = "xz",
185	.supported = 1
186};
187