2009-10-06 07:04:15 +04:00
/*
* Squashfs - a compressed read only filesystem for Linux
*
* Copyright ( c ) 2002 , 2003 , 2004 , 2005 , 2006 , 2007 , 2008 , 2009
2011-05-26 13:39:56 +04:00
* Phillip Lougher < phillip @ squashfs . org . uk >
2009-10-06 07:04:15 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2 ,
* or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* decompressor . c
*/
# include <linux/types.h>
# include <linux/mutex.h>
2011-02-28 04:45:42 +03:00
# include <linux/slab.h>
2009-10-06 07:04:15 +04:00
# include <linux/buffer_head.h>
# include "squashfs_fs.h"
# include "squashfs_fs_sb.h"
# include "decompressor.h"
# include "squashfs.h"
2013-11-18 06:59:12 +04:00
# include "page_actor.h"
2009-10-06 07:04:15 +04:00
/*
* This file ( and decompressor . h ) implements a decompressor framework for
* Squashfs , allowing multiple decompressors to be easily supported
*/
2009-10-14 06:58:11 +04:00
static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = {
2013-11-13 06:56:26 +04:00
NULL , NULL , NULL , NULL , LZMA_COMPRESSION , " lzma " , 0
2009-10-14 06:58:11 +04:00
} ;
2014-11-27 21:48:44 +03:00
# ifndef CONFIG_SQUASHFS_LZ4
static const struct squashfs_decompressor squashfs_lz4_comp_ops = {
NULL , NULL , NULL , NULL , LZ4_COMPRESSION , " lz4 " , 0
} ;
# endif
2010-08-05 05:29:59 +04:00
# ifndef CONFIG_SQUASHFS_LZO
2011-01-05 21:23:53 +03:00
static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
2013-11-13 06:56:26 +04:00
NULL , NULL , NULL , NULL , LZO_COMPRESSION , " lzo " , 0
2009-10-14 06:58:11 +04:00
} ;
2010-08-05 05:29:59 +04:00
# endif
2009-10-14 06:58:11 +04:00
2010-12-09 05:08:31 +03:00
# ifndef CONFIG_SQUASHFS_XZ
static const struct squashfs_decompressor squashfs_xz_comp_ops = {
2013-11-13 06:56:26 +04:00
NULL , NULL , NULL , NULL , XZ_COMPRESSION , " xz " , 0
2010-12-09 05:08:31 +03:00
} ;
# endif
2011-07-22 06:01:28 +04:00
# ifndef CONFIG_SQUASHFS_ZLIB
static const struct squashfs_decompressor squashfs_zlib_comp_ops = {
2013-11-13 06:56:26 +04:00
NULL , NULL , NULL , NULL , ZLIB_COMPRESSION , " zlib " , 0
2011-07-22 06:01:28 +04:00
} ;
# endif
2009-10-06 07:04:15 +04:00
static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
2013-11-13 06:56:26 +04:00
NULL , NULL , NULL , NULL , 0 , " unknown " , 0
2009-10-06 07:04:15 +04:00
} ;
static const struct squashfs_decompressor * decompressor [ ] = {
& squashfs_zlib_comp_ops ,
2014-11-27 21:48:44 +03:00
& squashfs_lz4_comp_ops ,
2010-08-05 05:29:59 +04:00
& squashfs_lzo_comp_ops ,
2010-12-09 05:08:31 +03:00
& squashfs_xz_comp_ops ,
2011-01-05 21:23:53 +03:00
& squashfs_lzma_unsupported_comp_ops ,
2009-10-06 07:04:15 +04:00
& squashfs_unknown_comp_ops
} ;
const struct squashfs_decompressor * squashfs_lookup_decompressor ( int id )
{
int i ;
for ( i = 0 ; decompressor [ i ] - > id ; i + + )
if ( id = = decompressor [ i ] - > id )
break ;
return decompressor [ i ] ;
}
2011-02-28 04:45:42 +03:00
2013-11-13 06:56:26 +04:00
static void * get_comp_opts ( struct super_block * sb , unsigned short flags )
2011-02-28 04:45:42 +03:00
{
struct squashfs_sb_info * msblk = sb - > s_fs_info ;
2013-11-13 06:56:26 +04:00
void * buffer = NULL , * comp_opts ;
2013-11-18 06:59:12 +04:00
struct squashfs_page_actor * actor = NULL ;
2011-02-28 04:45:42 +03:00
int length = 0 ;
/*
* Read decompressor specific options from file system if present
*/
if ( SQUASHFS_COMP_OPTS ( flags ) ) {
buffer = kmalloc ( PAGE_CACHE_SIZE , GFP_KERNEL ) ;
2013-11-13 06:56:26 +04:00
if ( buffer = = NULL ) {
comp_opts = ERR_PTR ( - ENOMEM ) ;
goto out ;
}
2011-02-28 04:45:42 +03:00
2013-11-18 06:59:12 +04:00
actor = squashfs_page_actor_init ( & buffer , 1 , 0 ) ;
if ( actor = = NULL ) {
comp_opts = ERR_PTR ( - ENOMEM ) ;
goto out ;
}
length = squashfs_read_data ( sb ,
sizeof ( struct squashfs_super_block ) , 0 , NULL , actor ) ;
2011-02-28 04:45:42 +03:00
if ( length < 0 ) {
2013-11-13 06:56:26 +04:00
comp_opts = ERR_PTR ( length ) ;
goto out ;
2011-02-28 04:45:42 +03:00
}
}
2013-11-13 06:56:26 +04:00
comp_opts = squashfs_comp_opts ( msblk , buffer , length ) ;
2011-02-28 04:45:42 +03:00
2013-11-13 06:56:26 +04:00
out :
2013-11-18 06:59:12 +04:00
kfree ( actor ) ;
2011-02-28 04:45:42 +03:00
kfree ( buffer ) ;
2013-11-13 06:56:26 +04:00
return comp_opts ;
}
void * squashfs_decompressor_setup ( struct super_block * sb , unsigned short flags )
{
struct squashfs_sb_info * msblk = sb - > s_fs_info ;
void * stream , * comp_opts = get_comp_opts ( sb , flags ) ;
if ( IS_ERR ( comp_opts ) )
return comp_opts ;
stream = squashfs_decompressor_create ( msblk , comp_opts ) ;
if ( IS_ERR ( stream ) )
kfree ( comp_opts ) ;
2011-02-28 04:45:42 +03:00
2013-11-13 06:56:26 +04:00
return stream ;
2011-02-28 04:45:42 +03:00
}