mirror of
https://github.com/ventoy/Ventoy.git
synced 2025-06-04 16:54:08 -04:00
initial commit
This commit is contained in:
parent
2090c6fa97
commit
05a1b863a6
487 changed files with 114253 additions and 0 deletions
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/Makefile
Normal file
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/Makefile
Normal file
|
@ -0,0 +1,365 @@
|
|||
###############################################
|
||||
# Compression build options #
|
||||
###############################################
|
||||
#
|
||||
#
|
||||
############# Building gzip support ###########
|
||||
#
|
||||
# Gzip support is by default enabled, and the compression type default
|
||||
# (COMP_DEFAULT) is gzip.
|
||||
#
|
||||
# If you don't want/need gzip support then comment out the GZIP SUPPORT line
|
||||
# below, and change COMP_DEFAULT to one of the compression types you have
|
||||
# selected.
|
||||
#
|
||||
# Obviously, you must select at least one of the available gzip, lzma, lzo
|
||||
# compression types.
|
||||
#
|
||||
GZIP_SUPPORT = 1
|
||||
|
||||
########### Building XZ support #############
|
||||
#
|
||||
# LZMA2 compression.
|
||||
#
|
||||
# XZ Utils liblzma (http://tukaani.org/xz/) is supported
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install the library and uncomment
|
||||
# the XZ_SUPPORT line below.
|
||||
#
|
||||
XZ_SUPPORT = 1
|
||||
|
||||
|
||||
############ Building LZO support ##############
|
||||
#
|
||||
# The LZO library (http://www.oberhumer.com/opensource/lzo/) is supported.
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install the library and uncomment
|
||||
# the XZ_SUPPORT line below.
|
||||
#
|
||||
LZO_SUPPORT = 1
|
||||
|
||||
|
||||
########### Building LZ4 support #############
|
||||
#
|
||||
# Yann Collet's LZ4 tools are supported
|
||||
# LZ4 homepage: http://fastcompression.blogspot.com/p/lz4.html
|
||||
# LZ4 source repository: http://code.google.com/p/lz4
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install and uncomment
|
||||
# the LZ4_SUPPORT line below.
|
||||
#
|
||||
LZ4_SUPPORT = 1
|
||||
|
||||
|
||||
########### Building ZSTD support ############
|
||||
#
|
||||
# The ZSTD library is supported
|
||||
# ZSTD homepage: http://zstd.net
|
||||
# ZSTD source repository: https://github.com/facebook/zstd
|
||||
#
|
||||
# Development packages (libraries and header files) should be
|
||||
# supported by most modern distributions. Please refer to
|
||||
# your distribution package manager.
|
||||
#
|
||||
# To build install the library and uncomment
|
||||
# the XZ_SUPPORT line below.
|
||||
#
|
||||
ZSTD_SUPPORT = 1
|
||||
|
||||
|
||||
######## Specifying default compression ########
|
||||
#
|
||||
# The next line specifies which compression algorithm is used by default
|
||||
# in Mksquashfs. Obviously the compression algorithm must have been
|
||||
# selected to be built
|
||||
#
|
||||
COMP_DEFAULT = gzip
|
||||
|
||||
|
||||
###############################################
|
||||
# Extended attribute (XATTRs) build options #
|
||||
###############################################
|
||||
#
|
||||
# Building XATTR support for Mksquashfs and Unsquashfs
|
||||
#
|
||||
# If your C library or build/target environment doesn't support XATTRs then
|
||||
# comment out the next line to build Mksquashfs and Unsquashfs without XATTR
|
||||
# support
|
||||
XATTR_SUPPORT = 1
|
||||
|
||||
# Select whether you wish xattrs to be stored by Mksquashfs and extracted
|
||||
# by Unsquashfs by default. If selected users can disable xattr support by
|
||||
# using the -no-xattrs option
|
||||
#
|
||||
# If unselected, Mksquashfs/Unsquashfs won't store and extract xattrs by
|
||||
# default. Users can enable xattrs by using the -xattrs option.
|
||||
XATTR_DEFAULT = 1
|
||||
|
||||
|
||||
###############################################
|
||||
# Reproducible Image options #
|
||||
###############################################
|
||||
#
|
||||
# Select whether you wish reproducible builds by default. If selected users
|
||||
# can disable reproducible builds using the not-reproducible option.
|
||||
# If not selected, users can enable reproducible builds using the
|
||||
# -reproducible option
|
||||
REPRODUCIBLE_DEFAULT = 1
|
||||
|
||||
|
||||
###############################################
|
||||
# Obsolete options #
|
||||
###############################################
|
||||
|
||||
########### Building LZMA support #############
|
||||
#
|
||||
# LZMA1 compression.
|
||||
#
|
||||
# LZMA1 compression is obsolete, and the newer and better XZ (LZMA2)
|
||||
# compression should be used in preference.
|
||||
#
|
||||
# Both XZ Utils liblzma (http://tukaani.org/xz/) and LZMA SDK
|
||||
# (http://www.7-zip.org/sdk.html) are supported
|
||||
#
|
||||
# To build using XZ Utils liblzma - install the library and uncomment
|
||||
# the LZMA_XZ_SUPPORT line below.
|
||||
#
|
||||
# To build using the LZMA SDK (4.65 used in development, other versions may
|
||||
# work) - download and unpack it, uncomment and set LZMA_DIR to unpacked source,
|
||||
# and uncomment the LZMA_SUPPORT line below.
|
||||
#
|
||||
LZMA_XZ_SUPPORT = 1
|
||||
#LZMA_SUPPORT = 1
|
||||
#LZMA_DIR = ../../../../LZMA/lzma465
|
||||
|
||||
###############################################
|
||||
# End of BUILD options section #
|
||||
###############################################
|
||||
|
||||
INCLUDEDIR = -I.
|
||||
INSTALL_DIR = /usr/local/bin
|
||||
|
||||
MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
|
||||
sort.o progressbar.o read_file.o info.o restore.o process_fragments.o \
|
||||
caches-queues-lists.o
|
||||
|
||||
UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
|
||||
unsquash-4.o unsquash-123.o unsquash-34.o swap.o compressor.o unsquashfs_info.o
|
||||
|
||||
CFLAGS ?= -Os
|
||||
CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
|
||||
-D_LARGEFILE_SOURCE -D_GNU_SOURCE -DCOMP_DEFAULT=\"$(COMP_DEFAULT)\" \
|
||||
-Wall
|
||||
|
||||
LIBS = -lpthread
|
||||
ifeq ($(GZIP_SUPPORT),1)
|
||||
CFLAGS += -DGZIP_SUPPORT
|
||||
MKSQUASHFS_OBJS += gzip_wrapper.o
|
||||
UNSQUASHFS_OBJS += gzip_wrapper.o
|
||||
LIBS += $(VTZLIB)
|
||||
COMPRESSORS += gzip
|
||||
endif
|
||||
|
||||
ifeq ($(LZMA_SUPPORT),1)
|
||||
LZMA_OBJS = $(LZMA_DIR)/C/Alloc.o $(LZMA_DIR)/C/LzFind.o \
|
||||
$(LZMA_DIR)/C/LzmaDec.o $(LZMA_DIR)/C/LzmaEnc.o $(LZMA_DIR)/C/LzmaLib.o
|
||||
INCLUDEDIR += -I$(LZMA_DIR)/C
|
||||
CFLAGS += -DLZMA_SUPPORT
|
||||
MKSQUASHFS_OBJS += lzma_wrapper.o $(LZMA_OBJS)
|
||||
UNSQUASHFS_OBJS += lzma_wrapper.o $(LZMA_OBJS)
|
||||
COMPRESSORS += lzma
|
||||
endif
|
||||
|
||||
ifeq ($(LZMA_XZ_SUPPORT),1)
|
||||
CFLAGS += -DLZMA_SUPPORT
|
||||
MKSQUASHFS_OBJS += lzma_xz_wrapper.o
|
||||
UNSQUASHFS_OBJS += lzma_xz_wrapper.o
|
||||
LIBS +=
|
||||
COMPRESSORS += lzma
|
||||
endif
|
||||
|
||||
ifeq ($(XZ_SUPPORT),1)
|
||||
CFLAGS += -DXZ_SUPPORT -I$(LZMA_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += xz_wrapper.o
|
||||
UNSQUASHFS_OBJS += xz_wrapper.o
|
||||
LIBS += $(LZMA_LIBDIR)/lib/liblzma.a
|
||||
COMPRESSORS += xz
|
||||
endif
|
||||
|
||||
ifeq ($(LZO_SUPPORT),1)
|
||||
CFLAGS += -DLZO_SUPPORT -I $(LZO_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += lzo_wrapper.o
|
||||
UNSQUASHFS_OBJS += lzo_wrapper.o
|
||||
LIBS += $(LZO_LIBDIR)/lib/liblzo2.a
|
||||
COMPRESSORS += lzo
|
||||
endif
|
||||
|
||||
ifeq ($(LZ4_SUPPORT),1)
|
||||
CFLAGS += -DLZ4_SUPPORT -I $(LZ4_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += lz4_wrapper.o
|
||||
UNSQUASHFS_OBJS += lz4_wrapper.o
|
||||
LIBS += $(LZ4_LIBDIR)/lib/liblz4.a
|
||||
COMPRESSORS += lz4
|
||||
endif
|
||||
|
||||
ifeq ($(ZSTD_SUPPORT),1)
|
||||
CFLAGS += -DZSTD_SUPPORT -I $(ZSTD_LIBDIR)/include
|
||||
MKSQUASHFS_OBJS += zstd_wrapper.o
|
||||
UNSQUASHFS_OBJS += zstd_wrapper.o
|
||||
LIBS += $(ZSTD_LIBDIR)/lib/libzstd.a
|
||||
COMPRESSORS += zstd
|
||||
endif
|
||||
|
||||
ifeq ($(XATTR_SUPPORT),1)
|
||||
ifeq ($(XATTR_DEFAULT),1)
|
||||
CFLAGS += -DXATTR_SUPPORT -DXATTR_DEFAULT
|
||||
else
|
||||
CFLAGS += -DXATTR_SUPPORT
|
||||
endif
|
||||
MKSQUASHFS_OBJS += xattr.o read_xattrs.o
|
||||
UNSQUASHFS_OBJS += read_xattrs.o unsquashfs_xattr.o
|
||||
endif
|
||||
|
||||
ifeq ($(REPRODUCIBLE_DEFAULT),1)
|
||||
CFLAGS += -DREPRODUCIBLE_DEFAULT
|
||||
endif
|
||||
|
||||
#
|
||||
# If LZMA_SUPPORT is specified then LZMA_DIR must be specified too
|
||||
#
|
||||
ifeq ($(LZMA_SUPPORT),1)
|
||||
ifndef LZMA_DIR
|
||||
$(error "LZMA_SUPPORT requires LZMA_DIR to be also defined")
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Both LZMA_XZ_SUPPORT and LZMA_SUPPORT cannot be specified
|
||||
#
|
||||
ifeq ($(LZMA_XZ_SUPPORT),1)
|
||||
ifeq ($(LZMA_SUPPORT),1)
|
||||
$(error "Both LZMA_XZ_SUPPORT and LZMA_SUPPORT cannot be specified")
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# At least one compressor must have been selected
|
||||
#
|
||||
ifndef COMPRESSORS
|
||||
$(error "No compressor selected! Select one or more of GZIP, LZMA, XZ, LZO, \
|
||||
LZ4 or ZSTD!")
|
||||
endif
|
||||
|
||||
#
|
||||
# COMP_DEFAULT should be defined
|
||||
#
|
||||
ifndef COMP_DEFAULT
|
||||
$(error "COMP_DEFAULT must be set to a compressor!")
|
||||
endif
|
||||
|
||||
#
|
||||
# COMP_DEFAULT must be a selected compressor
|
||||
#
|
||||
ifeq (, $(findstring $(COMP_DEFAULT), $(COMPRESSORS)))
|
||||
$(error "COMP_DEFAULT is set to ${COMP_DEFAULT}, which isn't selected to be \
|
||||
built!")
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: mksquashfs unsquashfs
|
||||
|
||||
mksquashfs: $(MKSQUASHFS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(MKSQUASHFS_OBJS) $(LIBS) -o $@
|
||||
|
||||
mksquashfs.o: Makefile mksquashfs.c squashfs_fs.h squashfs_swap.h mksquashfs.h \
|
||||
sort.h pseudo.h compressor.h xattr.h action.h error.h progressbar.h \
|
||||
info.h caches-queues-lists.h read_fs.h restore.h process_fragments.h
|
||||
|
||||
read_fs.o: read_fs.c squashfs_fs.h squashfs_swap.h compressor.h xattr.h \
|
||||
error.h mksquashfs.h
|
||||
|
||||
sort.o: sort.c squashfs_fs.h mksquashfs.h sort.h error.h progressbar.h
|
||||
|
||||
swap.o: swap.c
|
||||
|
||||
pseudo.o: pseudo.c pseudo.h error.h progressbar.h
|
||||
|
||||
compressor.o: Makefile compressor.c compressor.h squashfs_fs.h
|
||||
|
||||
xattr.o: xattr.c squashfs_fs.h squashfs_swap.h mksquashfs.h xattr.h error.h \
|
||||
progressbar.h
|
||||
|
||||
read_xattrs.o: read_xattrs.c squashfs_fs.h squashfs_swap.h xattr.h error.h
|
||||
|
||||
action.o: action.c squashfs_fs.h mksquashfs.h action.h error.h
|
||||
|
||||
progressbar.o: progressbar.c error.h
|
||||
|
||||
read_file.o: read_file.c error.h
|
||||
|
||||
info.o: info.c squashfs_fs.h mksquashfs.h error.h progressbar.h \
|
||||
caches-queues-lists.h
|
||||
|
||||
restore.o: restore.c caches-queues-lists.h squashfs_fs.h mksquashfs.h error.h \
|
||||
progressbar.h info.h
|
||||
|
||||
process_fragments.o: process_fragments.c process_fragments.h
|
||||
|
||||
caches-queues-lists.o: caches-queues-lists.c error.h caches-queues-lists.h
|
||||
|
||||
gzip_wrapper.o: gzip_wrapper.c squashfs_fs.h gzip_wrapper.h compressor.h
|
||||
|
||||
lzma_wrapper.o: lzma_wrapper.c compressor.h squashfs_fs.h
|
||||
|
||||
lzma_xz_wrapper.o: lzma_xz_wrapper.c compressor.h squashfs_fs.h
|
||||
|
||||
lzo_wrapper.o: lzo_wrapper.c squashfs_fs.h lzo_wrapper.h compressor.h
|
||||
|
||||
lz4_wrapper.o: lz4_wrapper.c squashfs_fs.h lz4_wrapper.h compressor.h
|
||||
|
||||
xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
|
||||
|
||||
unsquashfs: $(UNSQUASHFS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
|
||||
|
||||
unsquashfs.o: unsquashfs.h unsquashfs.c squashfs_fs.h squashfs_swap.h \
|
||||
squashfs_compat.h xattr.h read_fs.h compressor.h
|
||||
|
||||
unsquash-1.o: unsquashfs.h unsquash-1.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-2.o: unsquashfs.h unsquash-2.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-3.o: unsquashfs.h unsquash-3.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-4.o: unsquashfs.h unsquash-4.c squashfs_fs.h squashfs_swap.h \
|
||||
read_fs.h
|
||||
|
||||
unsquash-123.o: unsquashfs.h unsquash-123.c squashfs_fs.h squashfs_compat.h
|
||||
|
||||
unsquash-34.o: unsquashfs.h unsquash-34.c
|
||||
|
||||
unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h
|
||||
|
||||
unsquashfs_info.o: unsquashfs.h squashfs_fs.h
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -f *.o mksquashfs unsquashfs
|
||||
|
||||
.PHONY: install
|
||||
install: mksquashfs unsquashfs
|
||||
mkdir -p $(INSTALL_DIR)
|
||||
cp mksquashfs $(INSTALL_DIR)
|
||||
cp unsquashfs $(INSTALL_DIR)
|
3266
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.c
Normal file
3266
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.c
Normal file
File diff suppressed because it is too large
Load diff
328
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.h
Normal file
328
SQUASHFS/squashfs-tools-4.4/squashfs-tools/action.h
Normal file
|
@ -0,0 +1,328 @@
|
|||
#ifndef ACTION_H
|
||||
#define ACTION_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* action.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lexical analyser definitions
|
||||
*/
|
||||
#define TOK_OPEN_BRACKET 0
|
||||
#define TOK_CLOSE_BRACKET 1
|
||||
#define TOK_AND 2
|
||||
#define TOK_OR 3
|
||||
#define TOK_NOT 4
|
||||
#define TOK_COMMA 5
|
||||
#define TOK_AT 6
|
||||
#define TOK_WHITE_SPACE 7
|
||||
#define TOK_STRING 8
|
||||
#define TOK_EOF 9
|
||||
|
||||
#define TOK_TO_STR(OP, S) ({ \
|
||||
char *s; \
|
||||
switch(OP) { \
|
||||
case TOK_EOF: \
|
||||
s = "EOF"; \
|
||||
break; \
|
||||
case TOK_STRING: \
|
||||
s = S; \
|
||||
break; \
|
||||
default: \
|
||||
s = token_table[OP].string; \
|
||||
break; \
|
||||
} \
|
||||
s; \
|
||||
})
|
||||
|
||||
|
||||
struct token_entry {
|
||||
char *string;
|
||||
int token;
|
||||
int size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Expression parser definitions
|
||||
*/
|
||||
#define OP_TYPE 0
|
||||
#define ATOM_TYPE 1
|
||||
#define UNARY_TYPE 2
|
||||
|
||||
#define SYNTAX_ERROR(S, ARGS...) { \
|
||||
char *src = strdup(source); \
|
||||
src[cur_ptr - source] = '\0'; \
|
||||
fprintf(stderr, "Failed to parse action \"%s\"\n", source); \
|
||||
fprintf(stderr, "Syntax error: "S, ##ARGS); \
|
||||
fprintf(stderr, "Got here \"%s\"\n", src); \
|
||||
free(src); \
|
||||
}
|
||||
|
||||
#define TEST_SYNTAX_ERROR(TEST, ARG, S, ARGS...) { \
|
||||
char *src = strdup(source); \
|
||||
src[cur_ptr - source] = '\0'; \
|
||||
fprintf(stderr, "Failed to parse action \"%s\"\n", source); \
|
||||
fprintf(stderr, "Syntax error in \"%s()\", arg %d: "S, TEST->name, \
|
||||
ARG, ##ARGS); \
|
||||
fprintf(stderr, "Got here \"%s\"\n", src); \
|
||||
free(src); \
|
||||
}
|
||||
|
||||
struct expr;
|
||||
|
||||
struct expr_op {
|
||||
struct expr *lhs;
|
||||
struct expr *rhs;
|
||||
int op;
|
||||
};
|
||||
|
||||
|
||||
struct atom {
|
||||
struct test_entry *test;
|
||||
int args;
|
||||
char **argv;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
struct unary_op {
|
||||
struct expr *expr;
|
||||
int op;
|
||||
};
|
||||
|
||||
|
||||
struct expr {
|
||||
int type;
|
||||
union {
|
||||
struct atom atom;
|
||||
struct expr_op expr_op;
|
||||
struct unary_op unary_op;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Test operation definitions
|
||||
*/
|
||||
#define NUM_EQ 1
|
||||
#define NUM_LESS 2
|
||||
#define NUM_GREATER 3
|
||||
|
||||
struct test_number_arg {
|
||||
long long size;
|
||||
int range;
|
||||
};
|
||||
|
||||
struct test_range_args {
|
||||
long long start;
|
||||
long long end;
|
||||
};
|
||||
|
||||
struct action;
|
||||
struct action_data;
|
||||
|
||||
struct test_entry {
|
||||
char *name;
|
||||
int args;
|
||||
int (*fn)(struct atom *, struct action_data *);
|
||||
int (*parse_args)(struct test_entry *, struct atom *);
|
||||
int exclude_ok;
|
||||
int handle_logging;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Type test specific definitions
|
||||
*/
|
||||
struct type_entry {
|
||||
int value;
|
||||
char type;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Action definitions
|
||||
*/
|
||||
#define FRAGMENT_ACTION 0
|
||||
#define EXCLUDE_ACTION 1
|
||||
#define FRAGMENTS_ACTION 2
|
||||
#define NO_FRAGMENTS_ACTION 3
|
||||
#define ALWAYS_FRAGS_ACTION 4
|
||||
#define NO_ALWAYS_FRAGS_ACTION 5
|
||||
#define COMPRESSED_ACTION 6
|
||||
#define UNCOMPRESSED_ACTION 7
|
||||
#define UID_ACTION 8
|
||||
#define GID_ACTION 9
|
||||
#define GUID_ACTION 10
|
||||
#define MODE_ACTION 11
|
||||
#define EMPTY_ACTION 12
|
||||
#define MOVE_ACTION 13
|
||||
#define PRUNE_ACTION 14
|
||||
#define NOOP_ACTION 15
|
||||
|
||||
/*
|
||||
* Define what file types each action operates over
|
||||
*/
|
||||
#define ACTION_DIR 1
|
||||
#define ACTION_REG 2
|
||||
#define ACTION_ALL_LNK 3
|
||||
#define ACTION_ALL 4
|
||||
#define ACTION_LNK 5
|
||||
|
||||
|
||||
/*
|
||||
* Action logging requested, specified by the various
|
||||
* -action, -true-action, -false-action and -verbose-action
|
||||
* options
|
||||
*/
|
||||
#define ACTION_LOG_NONE 0
|
||||
#define ACTION_LOG_TRUE 1
|
||||
#define ACTION_LOG_FALSE 2
|
||||
#define ACTION_LOG_VERBOSE ACTION_LOG_TRUE | ACTION_LOG_FALSE
|
||||
|
||||
struct action_entry {
|
||||
char *name;
|
||||
int type;
|
||||
int args;
|
||||
int file_types;
|
||||
int (*parse_args)(struct action_entry *, int, char **, void **);
|
||||
void (*run_action)(struct action *, struct dir_ent *);
|
||||
};
|
||||
|
||||
|
||||
struct action_data {
|
||||
int depth;
|
||||
char *name;
|
||||
char *pathname;
|
||||
char *subpath;
|
||||
struct stat *buf;
|
||||
struct dir_ent *dir_ent;
|
||||
struct dir_info *root;
|
||||
};
|
||||
|
||||
|
||||
struct action {
|
||||
int type;
|
||||
struct action_entry *action;
|
||||
int args;
|
||||
char **argv;
|
||||
struct expr *expr;
|
||||
void *data;
|
||||
int verbose;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Uid/gid action specific definitions
|
||||
*/
|
||||
struct uid_info {
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
struct gid_info {
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
struct guid_info {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Mode action specific definitions
|
||||
*/
|
||||
#define ACTION_MODE_SET 0
|
||||
#define ACTION_MODE_ADD 1
|
||||
#define ACTION_MODE_REM 2
|
||||
#define ACTION_MODE_OCT 3
|
||||
|
||||
struct mode_data {
|
||||
struct mode_data *next;
|
||||
int operation;
|
||||
int mode;
|
||||
unsigned int mask;
|
||||
char X;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Empty action specific definitions
|
||||
*/
|
||||
#define EMPTY_ALL 0
|
||||
#define EMPTY_SOURCE 1
|
||||
#define EMPTY_EXCLUDED 2
|
||||
|
||||
struct empty_data {
|
||||
int val;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Move action specific definitions
|
||||
*/
|
||||
#define ACTION_MOVE_RENAME 1
|
||||
#define ACTION_MOVE_MOVE 2
|
||||
|
||||
struct move_ent {
|
||||
int ops;
|
||||
struct dir_ent *dir_ent;
|
||||
char *name;
|
||||
struct dir_info *dest;
|
||||
struct move_ent *next;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Perm test function specific definitions
|
||||
*/
|
||||
#define PERM_ALL 1
|
||||
#define PERM_ANY 2
|
||||
#define PERM_EXACT 3
|
||||
|
||||
struct perm_data {
|
||||
int op;
|
||||
int mode;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* External function definitions
|
||||
*/
|
||||
extern int parse_action(char *, int verbose);
|
||||
extern void dump_actions();
|
||||
extern void *eval_frag_actions(struct dir_info *, struct dir_ent *);
|
||||
extern void *get_frag_action(void *);
|
||||
extern int eval_exclude_actions(char *, char *, char *, struct stat *, int,
|
||||
struct dir_ent *);
|
||||
extern void eval_actions(struct dir_info *, struct dir_ent *);
|
||||
extern int eval_empty_actions(struct dir_info *, struct dir_ent *dir_ent);
|
||||
extern void eval_move_actions(struct dir_info *, struct dir_ent *);
|
||||
extern int eval_prune_actions(struct dir_info *, struct dir_ent *);
|
||||
extern void do_move_actions();
|
||||
extern int read_bytes(int, void *, int);
|
||||
extern int actions();
|
||||
extern int move_actions();
|
||||
extern int empty_actions();
|
||||
extern int read_action_file(char *, int);
|
||||
extern int exclude_actions();
|
||||
extern int prune_actions();
|
||||
#endif
|
35
SQUASHFS/squashfs-tools-4.4/squashfs-tools/build.sh
Normal file
35
SQUASHFS/squashfs-tools-4.4/squashfs-tools/build.sh
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
export LZMA_LIBDIR=$PWD/../../LIB/LZMA
|
||||
export LZ4_LIBDIR=$PWD/../../LIB/LZ4
|
||||
export ZSTD_LIBDIR=$PWD/../../LIB/ZSTD
|
||||
export LZO_LIBDIR=$PWD/../../LIB/LZO
|
||||
|
||||
if [ -e /lib64/libz.a ]; then
|
||||
export VTZLIB=/lib64/libz.a
|
||||
elif [ -e /lib/libz.a ]; then
|
||||
export VTZLIB=/lib/libz.a
|
||||
elif [ -e /usr/lib/libz.a ]; then
|
||||
export VTZLIB=/usr/lib/libz.a
|
||||
fi
|
||||
|
||||
rm -f unsquashfs
|
||||
make clean
|
||||
make -e unsquashfs
|
||||
|
||||
if [ -e unsquashfs ]; then
|
||||
strip --strip-all unsquashfs
|
||||
echo -e "\n========== SUCCESS ============\n"
|
||||
else
|
||||
echo -e "\n========== FAILED ============\n"
|
||||
fi
|
||||
|
||||
if uname -a | egrep -q 'x86_64|amd64'; then
|
||||
name=unsquashfs_64
|
||||
else
|
||||
name=unsquashfs_32
|
||||
fi
|
||||
|
||||
rm -f ../../$name
|
||||
cp -a unsquashfs ../../$name
|
||||
|
642
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.c
Normal file
642
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.c
Normal file
|
@ -0,0 +1,642 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* caches-queues-lists.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "caches-queues-lists.h"
|
||||
|
||||
extern int add_overflow(int, int);
|
||||
extern int multiply_overflow(int, int);
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
struct queue *queue_init(int size)
|
||||
{
|
||||
struct queue *queue = malloc(sizeof(struct queue));
|
||||
|
||||
if(queue == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
if(add_overflow(size, 1) ||
|
||||
multiply_overflow(size + 1, sizeof(void *)))
|
||||
BAD_ERROR("Size too large in queue_init\n");
|
||||
|
||||
queue->data = malloc(sizeof(void *) * (size + 1));
|
||||
if(queue->data == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
queue->size = size + 1;
|
||||
queue->readp = queue->writep = 0;
|
||||
pthread_mutex_init(&queue->mutex, NULL);
|
||||
pthread_cond_init(&queue->empty, NULL);
|
||||
pthread_cond_init(&queue->full, NULL);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
||||
void queue_put(struct queue *queue, void *data)
|
||||
{
|
||||
int nextp;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
|
||||
pthread_cond_wait(&queue->full, &queue->mutex);
|
||||
|
||||
queue->data[queue->writep] = data;
|
||||
queue->writep = nextp;
|
||||
pthread_cond_signal(&queue->empty);
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void *queue_get(struct queue *queue)
|
||||
{
|
||||
void *data;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
while(queue->readp == queue->writep)
|
||||
pthread_cond_wait(&queue->empty, &queue->mutex);
|
||||
|
||||
data = queue->data[queue->readp];
|
||||
queue->readp = (queue->readp + 1) % queue->size;
|
||||
pthread_cond_signal(&queue->full);
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
int queue_empty(struct queue *queue)
|
||||
{
|
||||
int empty;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
empty = queue->readp == queue->writep;
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
void queue_flush(struct queue *queue)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
queue->readp = queue->writep;
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void dump_queue(struct queue *queue)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
printf("\tMax size %d, size %d%s\n", queue->size - 1,
|
||||
queue->readp <= queue->writep ? queue->writep - queue->readp :
|
||||
queue->size - queue->readp + queue->writep,
|
||||
queue->readp == queue->writep ? " (EMPTY)" :
|
||||
((queue->writep + 1) % queue->size) == queue->readp ?
|
||||
" (FULL)" : "");
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
/* define seq queue hash tables */
|
||||
#define CALCULATE_SEQ_HASH(N) CALCULATE_HASH(N)
|
||||
|
||||
/* Called with the seq queue mutex held */
|
||||
INSERT_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq)
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
REMOVE_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq);
|
||||
|
||||
|
||||
struct seq_queue *seq_queue_init()
|
||||
{
|
||||
struct seq_queue *queue = malloc(sizeof(struct seq_queue));
|
||||
if(queue == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memset(queue, 0, sizeof(struct seq_queue));
|
||||
|
||||
pthread_mutex_init(&queue->mutex, NULL);
|
||||
pthread_cond_init(&queue->wait, NULL);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
||||
void seq_queue_put(struct seq_queue *queue, struct file_buffer *entry)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
insert_seq_hash_table(queue, entry);
|
||||
|
||||
if(entry->fragment)
|
||||
queue->fragment_count ++;
|
||||
else
|
||||
queue->block_count ++;
|
||||
|
||||
if(entry->sequence == queue->sequence)
|
||||
pthread_cond_signal(&queue->wait);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *seq_queue_get(struct seq_queue *queue)
|
||||
{
|
||||
/*
|
||||
* Return next buffer from queue in sequence order (queue->sequence). If
|
||||
* found return it, otherwise wait for it to arrive.
|
||||
*/
|
||||
int hash = CALCULATE_SEQ_HASH(queue->sequence);
|
||||
struct file_buffer *entry;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
while(1) {
|
||||
for(entry = queue->hash_table[hash]; entry;
|
||||
entry = entry->seq_next)
|
||||
if(entry->sequence == queue->sequence)
|
||||
break;
|
||||
|
||||
if(entry) {
|
||||
/*
|
||||
* found the buffer in the queue, decrement the
|
||||
* appropriate count, and remove from hash list
|
||||
*/
|
||||
if(entry->fragment)
|
||||
queue->fragment_count --;
|
||||
else
|
||||
queue->block_count --;
|
||||
|
||||
remove_seq_hash_table(queue, entry);
|
||||
|
||||
queue->sequence ++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* entry not found, wait for it to arrive */
|
||||
pthread_cond_wait(&queue->wait, &queue->mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
void seq_queue_flush(struct seq_queue *queue)
|
||||
{
|
||||
int i;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
for(i = 0; i < HASH_SIZE; i++)
|
||||
queue->hash_table[i] = NULL;
|
||||
|
||||
queue->fragment_count = queue->block_count = 0;
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void dump_seq_queue(struct seq_queue *queue, int fragment_queue)
|
||||
{
|
||||
int size;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
|
||||
size = fragment_queue ? queue->fragment_count : queue->block_count;
|
||||
|
||||
printf("\tMax size unlimited, size %d%s\n", size,
|
||||
size == 0 ? " (EMPTY)" : "");
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
/* define cache hash tables */
|
||||
#define CALCULATE_CACHE_HASH(N) CALCULATE_HASH(llabs(N))
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
INSERT_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash)
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
REMOVE_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash);
|
||||
|
||||
/* define cache free list */
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
INSERT_LIST(free, struct file_buffer)
|
||||
|
||||
/* Called with the cache mutex held */
|
||||
REMOVE_LIST(free, struct file_buffer)
|
||||
|
||||
|
||||
struct cache *cache_init(int buffer_size, int max_buffers, int noshrink_lookup,
|
||||
int first_freelist)
|
||||
{
|
||||
struct cache *cache = malloc(sizeof(struct cache));
|
||||
|
||||
if(cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
cache->max_buffers = max_buffers;
|
||||
cache->buffer_size = buffer_size;
|
||||
cache->count = 0;
|
||||
cache->used = 0;
|
||||
cache->free_list = NULL;
|
||||
|
||||
/*
|
||||
* The cache will grow up to max_buffers in size in response to
|
||||
* an increase in readhead/number of buffers in flight. But
|
||||
* once the outstanding buffers gets returned, we can either elect
|
||||
* to shrink the cache, or to put the freed blocks onto a free list.
|
||||
*
|
||||
* For the caches where we want to do lookup (fragment/writer),
|
||||
* a don't shrink policy is best, for the reader cache it
|
||||
* makes no sense to keep buffers around longer than necessary as
|
||||
* we don't do any lookup on those blocks.
|
||||
*/
|
||||
cache->noshrink_lookup = noshrink_lookup;
|
||||
|
||||
/*
|
||||
* The default use freelist before growing cache policy behaves
|
||||
* poorly with appending - with many duplicates the caches
|
||||
* do not grow due to the fact that large queues of outstanding
|
||||
* fragments/writer blocks do not occur, leading to small caches
|
||||
* and un-uncessary performance loss to frequent cache
|
||||
* replacement in the small caches. Therefore with appending
|
||||
* change the policy to grow the caches before reusing blocks
|
||||
* from the freelist
|
||||
*/
|
||||
cache->first_freelist = first_freelist;
|
||||
|
||||
memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
|
||||
pthread_mutex_init(&cache->mutex, NULL);
|
||||
pthread_cond_init(&cache->wait_for_free, NULL);
|
||||
pthread_cond_init(&cache->wait_for_unlock, NULL);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_lookup(struct cache *cache, long long index)
|
||||
{
|
||||
/* Lookup block in the cache, if found return with usage count
|
||||
* incremented, if not found return NULL */
|
||||
int hash = CALCULATE_CACHE_HASH(index);
|
||||
struct file_buffer *entry;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
|
||||
if(entry->index == index)
|
||||
break;
|
||||
|
||||
if(entry) {
|
||||
/* found the block in the cache, increment used count and
|
||||
* if necessary remove from free list so it won't disappear
|
||||
*/
|
||||
if(entry->used == 0) {
|
||||
remove_free_list(&cache->free_list, entry);
|
||||
cache->used ++;
|
||||
}
|
||||
entry->used ++;
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *cache_freelist(struct cache *cache)
|
||||
{
|
||||
struct file_buffer *entry = cache->free_list;
|
||||
|
||||
remove_free_list(&cache->free_list, entry);
|
||||
|
||||
/* a block on the free_list is hashed */
|
||||
remove_cache_hash_table(cache, entry);
|
||||
|
||||
cache->used ++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *cache_alloc(struct cache *cache)
|
||||
{
|
||||
struct file_buffer *entry = malloc(sizeof(struct file_buffer) +
|
||||
cache->buffer_size);
|
||||
if(entry == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
entry->cache = cache;
|
||||
entry->free_prev = entry->free_next = NULL;
|
||||
cache->count ++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *_cache_get(struct cache *cache, long long index,
|
||||
int hash)
|
||||
{
|
||||
/* Get a free block out of the cache indexed on index. */
|
||||
struct file_buffer *entry = NULL;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
while(1) {
|
||||
if(cache->noshrink_lookup) {
|
||||
/* first try to get a block from the free list */
|
||||
if(cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
else if(cache->count < cache->max_buffers) {
|
||||
entry = cache_alloc(cache);
|
||||
cache->used ++;
|
||||
} else if(!cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
} else { /* shrinking non-lookup cache */
|
||||
if(cache->count < cache->max_buffers) {
|
||||
entry = cache_alloc(cache);
|
||||
if(cache->count > cache->max_count)
|
||||
cache->max_count = cache->count;
|
||||
}
|
||||
}
|
||||
|
||||
if(entry)
|
||||
break;
|
||||
|
||||
/* wait for a block */
|
||||
pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
|
||||
}
|
||||
|
||||
/* initialise block and if hash is set insert into the hash table */
|
||||
entry->used = 1;
|
||||
entry->locked = FALSE;
|
||||
entry->wait_on_unlock = FALSE;
|
||||
entry->error = FALSE;
|
||||
if(hash) {
|
||||
entry->index = index;
|
||||
insert_cache_hash_table(cache, entry);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_get(struct cache *cache, long long index)
|
||||
{
|
||||
return _cache_get(cache, index, 1);
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_get_nohash(struct cache *cache)
|
||||
{
|
||||
return _cache_get(cache, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void cache_hash(struct file_buffer *entry, long long index)
|
||||
{
|
||||
struct cache *cache = entry->cache;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
entry->index = index;
|
||||
insert_cache_hash_table(cache, entry);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void cache_block_put(struct file_buffer *entry)
|
||||
{
|
||||
struct cache *cache;
|
||||
|
||||
/*
|
||||
* Finished with this cache entry, once the usage count reaches zero it
|
||||
* can be reused.
|
||||
*
|
||||
* If noshrink_lookup is set, put the block onto the free list.
|
||||
* As blocks remain accessible via the hash table they can be found
|
||||
* getting a new lease of life before they are reused.
|
||||
*
|
||||
* if noshrink_lookup is not set then shrink the cache.
|
||||
*/
|
||||
|
||||
if(entry == NULL)
|
||||
return;
|
||||
|
||||
cache = entry->cache;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
entry->used --;
|
||||
if(entry->used == 0) {
|
||||
if(cache->noshrink_lookup) {
|
||||
insert_free_list(&cache->free_list, entry);
|
||||
cache->used --;
|
||||
} else {
|
||||
free(entry);
|
||||
cache->count --;
|
||||
}
|
||||
|
||||
/* One or more threads may be waiting on this block */
|
||||
pthread_cond_signal(&cache->wait_for_free);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void dump_cache(struct cache *cache)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
if(cache->noshrink_lookup)
|
||||
printf("\tMax buffers %d, Current size %d, Used %d, %s\n",
|
||||
cache->max_buffers, cache->count, cache->used,
|
||||
cache->free_list ? "Free buffers" : "No free buffers");
|
||||
else
|
||||
printf("\tMax buffers %d, Current size %d, Maximum historical "
|
||||
"size %d\n", cache->max_buffers, cache->count,
|
||||
cache->max_count);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_get_nowait(struct cache *cache, long long index)
|
||||
{
|
||||
struct file_buffer *entry = NULL;
|
||||
/*
|
||||
* block doesn't exist, create it, but return it with the
|
||||
* locked flag set, so nothing tries to use it while it doesn't
|
||||
* contain data.
|
||||
*
|
||||
* If there's no space in the cache then return NULL.
|
||||
*/
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
/* first try to get a block from the free list */
|
||||
if(cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
else if(cache->count < cache->max_buffers) {
|
||||
entry = cache_alloc(cache);
|
||||
cache->used ++;
|
||||
} else if(!cache->first_freelist && cache->free_list)
|
||||
entry = cache_freelist(cache);
|
||||
|
||||
if(entry) {
|
||||
/* initialise block and insert into the hash table */
|
||||
entry->used = 1;
|
||||
entry->locked = TRUE;
|
||||
entry->wait_on_unlock = FALSE;
|
||||
entry->error = FALSE;
|
||||
entry->index = index;
|
||||
insert_cache_hash_table(cache, entry);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *cache_lookup_nowait(struct cache *cache, long long index,
|
||||
char *locked)
|
||||
{
|
||||
/*
|
||||
* Lookup block in the cache, if found return it with the locked flag
|
||||
* indicating whether it is currently locked. In both cases increment
|
||||
* the used count.
|
||||
*
|
||||
* If it doesn't exist in the cache return NULL;
|
||||
*/
|
||||
int hash = CALCULATE_CACHE_HASH(index);
|
||||
struct file_buffer *entry;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
/* first check if the entry already exists */
|
||||
for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
|
||||
if(entry->index == index)
|
||||
break;
|
||||
|
||||
if(entry) {
|
||||
if(entry->used == 0) {
|
||||
remove_free_list(&cache->free_list, entry);
|
||||
cache->used ++;
|
||||
}
|
||||
entry->used ++;
|
||||
*locked = entry->locked;
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
void cache_wait_unlock(struct file_buffer *buffer)
|
||||
{
|
||||
struct cache *cache = buffer->cache;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
while(buffer->locked) {
|
||||
/*
|
||||
* another thread is filling this in, wait until it
|
||||
* becomes unlocked. Used has been incremented to ensure it
|
||||
* doesn't get reused. By definition a block can't be
|
||||
* locked and unused, and so we don't need to worry
|
||||
* about it being on the freelist now, but, it may
|
||||
* become unused when unlocked unless used is
|
||||
* incremented
|
||||
*/
|
||||
buffer->wait_on_unlock = TRUE;
|
||||
pthread_cond_wait(&cache->wait_for_unlock, &cache->mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void cache_unlock(struct file_buffer *entry)
|
||||
{
|
||||
struct cache *cache = entry->cache;
|
||||
|
||||
/*
|
||||
* Unlock this locked cache entry. If anything is waiting for this
|
||||
* to become unlocked, wake it up.
|
||||
*/
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
|
||||
pthread_mutex_lock(&cache->mutex);
|
||||
|
||||
entry->locked = FALSE;
|
||||
|
||||
if(entry->wait_on_unlock) {
|
||||
entry->wait_on_unlock = FALSE;
|
||||
pthread_cond_broadcast(&cache->wait_for_unlock);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
199
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.h
Normal file
199
SQUASHFS/squashfs-tools-4.4/squashfs-tools/caches-queues-lists.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
#ifndef CACHES_QUEUES_LISTS_H
|
||||
#define CACHES_QUEUES_LISTS_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* caches-queues-lists.h
|
||||
*/
|
||||
|
||||
#define INSERT_LIST(NAME, TYPE) \
|
||||
void insert_##NAME##_list(TYPE **list, TYPE *entry) { \
|
||||
if(*list) { \
|
||||
entry->NAME##_next = *list; \
|
||||
entry->NAME##_prev = (*list)->NAME##_prev; \
|
||||
(*list)->NAME##_prev->NAME##_next = entry; \
|
||||
(*list)->NAME##_prev = entry; \
|
||||
} else { \
|
||||
*list = entry; \
|
||||
entry->NAME##_prev = entry->NAME##_next = entry; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define REMOVE_LIST(NAME, TYPE) \
|
||||
void remove_##NAME##_list(TYPE **list, TYPE *entry) { \
|
||||
if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \
|
||||
/* only this entry in the list */ \
|
||||
*list = NULL; \
|
||||
} else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \
|
||||
/* more than one entry in the list */ \
|
||||
entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \
|
||||
entry->NAME##_prev->NAME##_next = entry->NAME##_next; \
|
||||
if(*list == entry) \
|
||||
*list = entry->NAME##_next; \
|
||||
} \
|
||||
entry->NAME##_prev = entry->NAME##_next = NULL; \
|
||||
}
|
||||
|
||||
|
||||
#define INSERT_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
|
||||
void insert_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
|
||||
{ \
|
||||
int hash = HASH_FUNCTION(entry->FIELD); \
|
||||
\
|
||||
entry->LINK##_next = container->hash_table[hash]; \
|
||||
container->hash_table[hash] = entry; \
|
||||
entry->LINK##_prev = NULL; \
|
||||
if(entry->LINK##_next) \
|
||||
entry->LINK##_next->LINK##_prev = entry; \
|
||||
}
|
||||
|
||||
|
||||
#define REMOVE_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \
|
||||
void remove_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \
|
||||
{ \
|
||||
if(entry->LINK##_prev) \
|
||||
entry->LINK##_prev->LINK##_next = entry->LINK##_next; \
|
||||
else \
|
||||
container->hash_table[HASH_FUNCTION(entry->FIELD)] = \
|
||||
entry->LINK##_next; \
|
||||
if(entry->LINK##_next) \
|
||||
entry->LINK##_next->LINK##_prev = entry->LINK##_prev; \
|
||||
\
|
||||
entry->LINK##_prev = entry->LINK##_next = NULL; \
|
||||
}
|
||||
|
||||
#define HASH_SIZE 65536
|
||||
#define CALCULATE_HASH(n) ((n) & 0xffff)
|
||||
|
||||
|
||||
/* struct describing a cache entry passed between threads */
|
||||
struct file_buffer {
|
||||
long long index;
|
||||
long long sequence;
|
||||
long long file_size;
|
||||
union {
|
||||
long long block;
|
||||
unsigned short checksum;
|
||||
};
|
||||
struct cache *cache;
|
||||
union {
|
||||
struct file_info *dupl_start;
|
||||
struct file_buffer *hash_next;
|
||||
};
|
||||
union {
|
||||
int duplicate;
|
||||
struct file_buffer *hash_prev;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
struct file_buffer *free_next;
|
||||
struct file_buffer *free_prev;
|
||||
};
|
||||
struct {
|
||||
struct file_buffer *seq_next;
|
||||
struct file_buffer *seq_prev;
|
||||
};
|
||||
};
|
||||
int size;
|
||||
int c_byte;
|
||||
char used;
|
||||
char fragment;
|
||||
char error;
|
||||
char locked;
|
||||
char wait_on_unlock;
|
||||
char noD;
|
||||
char data[0] __attribute__((aligned));
|
||||
};
|
||||
|
||||
|
||||
/* struct describing queues used to pass data between threads */
|
||||
struct queue {
|
||||
int size;
|
||||
int readp;
|
||||
int writep;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t empty;
|
||||
pthread_cond_t full;
|
||||
void **data;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* struct describing seq_queues used to pass data between the read
|
||||
* thread and the deflate and main threads
|
||||
*/
|
||||
struct seq_queue {
|
||||
int fragment_count;
|
||||
int block_count;
|
||||
long long sequence;
|
||||
struct file_buffer *hash_table[HASH_SIZE];
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t wait;
|
||||
};
|
||||
|
||||
|
||||
/* Cache status struct. Caches are used to keep
|
||||
track of memory buffers passed between different threads */
|
||||
struct cache {
|
||||
int max_buffers;
|
||||
int count;
|
||||
int buffer_size;
|
||||
int noshrink_lookup;
|
||||
int first_freelist;
|
||||
union {
|
||||
int used;
|
||||
int max_count;
|
||||
};
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t wait_for_free;
|
||||
pthread_cond_t wait_for_unlock;
|
||||
struct file_buffer *free_list;
|
||||
struct file_buffer *hash_table[HASH_SIZE];
|
||||
};
|
||||
|
||||
|
||||
extern struct queue *queue_init(int);
|
||||
extern void queue_put(struct queue *, void *);
|
||||
extern void *queue_get(struct queue *);
|
||||
extern int queue_empty(struct queue *);
|
||||
extern void queue_flush(struct queue *);
|
||||
extern void dump_queue(struct queue *);
|
||||
extern struct seq_queue *seq_queue_init();
|
||||
extern void seq_queue_put(struct seq_queue *, struct file_buffer *);
|
||||
extern void dump_seq_queue(struct seq_queue *, int);
|
||||
extern struct file_buffer *seq_queue_get(struct seq_queue *);
|
||||
extern void seq_queue_flush(struct seq_queue *);
|
||||
extern struct cache *cache_init(int, int, int, int);
|
||||
extern struct file_buffer *cache_lookup(struct cache *, long long);
|
||||
extern struct file_buffer *cache_get(struct cache *, long long);
|
||||
extern struct file_buffer *cache_get_nohash(struct cache *);
|
||||
extern void cache_hash(struct file_buffer *, long long);
|
||||
extern void cache_block_put(struct file_buffer *);
|
||||
extern void dump_cache(struct cache *);
|
||||
extern struct file_buffer *cache_get_nowait(struct cache *, long long);
|
||||
extern struct file_buffer *cache_lookup_nowait(struct cache *, long long,
|
||||
char *);
|
||||
extern void cache_wait_unlock(struct file_buffer *);
|
||||
extern void cache_unlock(struct file_buffer *);
|
||||
|
||||
extern int first_freelist;
|
||||
#endif
|
145
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.c
Normal file
145
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* compressor.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "compressor.h"
|
||||
#include "squashfs_fs.h"
|
||||
|
||||
#ifndef GZIP_SUPPORT
|
||||
static struct compressor gzip_comp_ops = {
|
||||
ZLIB_COMPRESSION, "gzip"
|
||||
};
|
||||
#else
|
||||
extern struct compressor gzip_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef LZMA_SUPPORT
|
||||
static struct compressor lzma_comp_ops = {
|
||||
LZMA_COMPRESSION, "lzma"
|
||||
};
|
||||
#else
|
||||
extern struct compressor lzma_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef LZO_SUPPORT
|
||||
static struct compressor lzo_comp_ops = {
|
||||
LZO_COMPRESSION, "lzo"
|
||||
};
|
||||
#else
|
||||
extern struct compressor lzo_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef LZ4_SUPPORT
|
||||
static struct compressor lz4_comp_ops = {
|
||||
LZ4_COMPRESSION, "lz4"
|
||||
};
|
||||
#else
|
||||
extern struct compressor lz4_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef XZ_SUPPORT
|
||||
static struct compressor xz_comp_ops = {
|
||||
XZ_COMPRESSION, "xz"
|
||||
};
|
||||
#else
|
||||
extern struct compressor xz_comp_ops;
|
||||
#endif
|
||||
|
||||
#ifndef ZSTD_SUPPORT
|
||||
static struct compressor zstd_comp_ops = {
|
||||
ZSTD_COMPRESSION, "zstd"
|
||||
};
|
||||
#else
|
||||
extern struct compressor zstd_comp_ops;
|
||||
#endif
|
||||
|
||||
static struct compressor unknown_comp_ops = {
|
||||
0, "unknown"
|
||||
};
|
||||
|
||||
|
||||
struct compressor *compressor[] = {
|
||||
&gzip_comp_ops,
|
||||
&lzma_comp_ops,
|
||||
&lzo_comp_ops,
|
||||
&lz4_comp_ops,
|
||||
&xz_comp_ops,
|
||||
&zstd_comp_ops,
|
||||
&unknown_comp_ops
|
||||
};
|
||||
|
||||
|
||||
struct compressor *lookup_compressor(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(strcmp(compressor[i]->name, name) == 0)
|
||||
break;
|
||||
|
||||
return compressor[i];
|
||||
}
|
||||
|
||||
|
||||
struct compressor *lookup_compressor_id(int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(id == compressor[i]->id)
|
||||
break;
|
||||
|
||||
return compressor[i];
|
||||
}
|
||||
|
||||
|
||||
void display_compressors(char *indent, char *def_comp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(compressor[i]->supported)
|
||||
fprintf(stderr, "%s\t%s%s\n", indent,
|
||||
compressor[i]->name,
|
||||
strcmp(compressor[i]->name, def_comp) == 0 ?
|
||||
" (default)" : "");
|
||||
}
|
||||
|
||||
|
||||
void display_compressor_usage(char *def_comp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; compressor[i]->id; i++)
|
||||
if(compressor[i]->supported) {
|
||||
char *str = strcmp(compressor[i]->name, def_comp) == 0 ?
|
||||
" (default)" : "";
|
||||
if(compressor[i]->usage) {
|
||||
fprintf(stderr, "\t%s%s\n",
|
||||
compressor[i]->name, str);
|
||||
compressor[i]->usage();
|
||||
} else
|
||||
fprintf(stderr, "\t%s (no options)%s\n",
|
||||
compressor[i]->name, str);
|
||||
}
|
||||
}
|
124
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.h
Normal file
124
SQUASHFS/squashfs-tools-4.4/squashfs-tools/compressor.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
#ifndef COMPRESSOR_H
|
||||
#define COMPRESSOR_H
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* compressor.h
|
||||
*/
|
||||
|
||||
struct compressor {
|
||||
int id;
|
||||
char *name;
|
||||
int supported;
|
||||
int (*init)(void **, int, int);
|
||||
int (*compress)(void *, void *, void *, int, int, int *);
|
||||
int (*uncompress)(void *, void *, int, int, int *);
|
||||
int (*options)(char **, int);
|
||||
int (*options_post)(int);
|
||||
void *(*dump_options)(int, int *);
|
||||
int (*extract_options)(int, void *, int);
|
||||
int (*check_options)(int, void *, int);
|
||||
void (*display_options)(void *, int);
|
||||
void (*usage)();
|
||||
};
|
||||
|
||||
extern struct compressor *lookup_compressor(char *);
|
||||
extern struct compressor *lookup_compressor_id(int);
|
||||
extern void display_compressors(char *, char *);
|
||||
extern void display_compressor_usage(char *);
|
||||
|
||||
static inline int compressor_init(struct compressor *comp, void **stream,
|
||||
int block_size, int datablock)
|
||||
{
|
||||
if(comp->init == NULL)
|
||||
return 0;
|
||||
return comp->init(stream, block_size, datablock);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_compress(struct compressor *comp, void *strm,
|
||||
void *dest, void *src, int size, int block_size, int *error)
|
||||
{
|
||||
return comp->compress(strm, dest, src, size, block_size, error);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_uncompress(struct compressor *comp, void *dest,
|
||||
void *src, int size, int block_size, int *error)
|
||||
{
|
||||
return comp->uncompress(dest, src, size, block_size, error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For the following functions please see the lzo, lz4 or xz
|
||||
* compressors for commented examples of how they are used.
|
||||
*/
|
||||
static inline int compressor_options(struct compressor *comp, char *argv[],
|
||||
int argc)
|
||||
{
|
||||
if(comp->options == NULL)
|
||||
return -1;
|
||||
|
||||
return comp->options(argv, argc);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_options_post(struct compressor *comp, int block_size)
|
||||
{
|
||||
if(comp->options_post == NULL)
|
||||
return 0;
|
||||
return comp->options_post(block_size);
|
||||
}
|
||||
|
||||
|
||||
static inline void *compressor_dump_options(struct compressor *comp,
|
||||
int block_size, int *size)
|
||||
{
|
||||
if(comp->dump_options == NULL)
|
||||
return NULL;
|
||||
return comp->dump_options(block_size, size);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_extract_options(struct compressor *comp,
|
||||
int block_size, void *buffer, int size)
|
||||
{
|
||||
if(comp->extract_options == NULL)
|
||||
return size ? -1 : 0;
|
||||
return comp->extract_options(block_size, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
static inline int compressor_check_options(struct compressor *comp,
|
||||
int block_size, void *buffer, int size)
|
||||
{
|
||||
if(comp->check_options == NULL)
|
||||
return 0;
|
||||
return comp->check_options(block_size, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
static inline void compressor_display_options(struct compressor *comp,
|
||||
void *buffer, int size)
|
||||
{
|
||||
if(comp->display_options != NULL)
|
||||
comp->display_options(buffer, size);
|
||||
}
|
||||
#endif
|
106
SQUASHFS/squashfs-tools-4.4/squashfs-tools/error.h
Normal file
106
SQUASHFS/squashfs-tools-4.4/squashfs-tools/error.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* error.h
|
||||
*/
|
||||
|
||||
extern int exit_on_error;
|
||||
|
||||
extern void prep_exit();
|
||||
extern void progressbar_error(char *fmt, ...);
|
||||
extern void progressbar_info(char *fmt, ...);
|
||||
|
||||
#ifdef SQUASHFS_TRACE
|
||||
#define TRACE(s, args...) \
|
||||
do { \
|
||||
progressbar_info("squashfs: "s, ## args);\
|
||||
} while(0)
|
||||
#else
|
||||
#define TRACE(s, args...)
|
||||
#endif
|
||||
|
||||
#define INFO(s, args...) \
|
||||
do {\
|
||||
if(!silent)\
|
||||
progressbar_info(s, ## args);\
|
||||
} while(0)
|
||||
|
||||
#define ERROR(s, args...) \
|
||||
do {\
|
||||
progressbar_error(s, ## args); \
|
||||
} while(0)
|
||||
|
||||
#define ERROR_START(s, args...) \
|
||||
do { \
|
||||
disable_progress_bar(); \
|
||||
fprintf(stderr, s, ## args); \
|
||||
} while(0)
|
||||
|
||||
#define ERROR_EXIT(s, args...) \
|
||||
do {\
|
||||
if (exit_on_error) { \
|
||||
fprintf(stderr, "\n"); \
|
||||
EXIT_MKSQUASHFS(); \
|
||||
} else { \
|
||||
fprintf(stderr, s, ## args); \
|
||||
enable_progress_bar(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define EXIT_MKSQUASHFS() \
|
||||
do {\
|
||||
prep_exit();\
|
||||
exit(1);\
|
||||
} while(0)
|
||||
|
||||
#define BAD_ERROR(s, args...) \
|
||||
do {\
|
||||
progressbar_error("FATAL ERROR:" s, ##args); \
|
||||
EXIT_MKSQUASHFS();\
|
||||
} while(0)
|
||||
|
||||
#define EXIT_UNSQUASH(s, args...) BAD_ERROR(s, ##args)
|
||||
|
||||
#define EXIT_UNSQUASH_IGNORE(s, args...) \
|
||||
do {\
|
||||
if(ignore_errors) \
|
||||
ERROR(s, ##args); \
|
||||
else \
|
||||
BAD_ERROR(s, ##args); \
|
||||
} while(0)
|
||||
|
||||
#define EXIT_UNSQUASH_STRICT(s, args...) \
|
||||
do {\
|
||||
if(!strict_errors) \
|
||||
ERROR(s, ##args); \
|
||||
else \
|
||||
BAD_ERROR(s, ##args); \
|
||||
} while(0)
|
||||
|
||||
#define MEM_ERROR() \
|
||||
do {\
|
||||
progressbar_error("FATAL ERROR: Out of memory (%s)\n", \
|
||||
__func__); \
|
||||
EXIT_MKSQUASHFS();\
|
||||
} while(0)
|
||||
#endif
|
32
SQUASHFS/squashfs-tools-4.4/squashfs-tools/fnmatch_compat.h
Normal file
32
SQUASHFS/squashfs-tools-4.4/squashfs-tools/fnmatch_compat.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef FNMATCH_COMPAT
|
||||
#define FNMATCH_COMPAT
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2015
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* fnmatch_compat.h
|
||||
*/
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
#ifndef FNM_EXTMATCH
|
||||
#define FNM_EXTMATCH 0
|
||||
#endif
|
||||
|
||||
#endif
|
500
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.c
Normal file
500
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.c
Normal file
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2010, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* gzip_wrapper.c
|
||||
*
|
||||
* Support for ZLIB compression http://www.zlib.net
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "gzip_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
static struct strategy strategy[] = {
|
||||
{ "default", Z_DEFAULT_STRATEGY, 0 },
|
||||
{ "filtered", Z_FILTERED, 0 },
|
||||
{ "huffman_only", Z_HUFFMAN_ONLY, 0 },
|
||||
{ "run_length_encoded", Z_RLE, 0 },
|
||||
{ "fixed", Z_FIXED, 0 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static int strategy_count = 0;
|
||||
|
||||
/* default compression level */
|
||||
static int compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
|
||||
|
||||
/* default window size */
|
||||
static int window_size = GZIP_DEFAULT_WINDOW_SIZE;
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The gzip_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int gzip_options(char *argv[], int argc)
|
||||
{
|
||||
if(strcmp(argv[0], "-Xcompression-level") == 0) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "gzip: -Xcompression-level missing "
|
||||
"compression level\n");
|
||||
fprintf(stderr, "gzip: -Xcompression-level it "
|
||||
"should be 1 >= n <= 9\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
compression_level = atoi(argv[1]);
|
||||
if(compression_level < 1 || compression_level > 9) {
|
||||
fprintf(stderr, "gzip: -Xcompression-level invalid, it "
|
||||
"should be 1 >= n <= 9\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if(strcmp(argv[0], "-Xwindow-size") == 0) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "gzip: -Xwindow-size missing window "
|
||||
" size\n");
|
||||
fprintf(stderr, "gzip: -Xwindow-size <window-size>\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
window_size = atoi(argv[1]);
|
||||
if(window_size < 8 || window_size > 15) {
|
||||
fprintf(stderr, "gzip: -Xwindow-size invalid, it "
|
||||
"should be 8 >= n <= 15\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if(strcmp(argv[0], "-Xstrategy") == 0) {
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "gzip: -Xstrategy missing "
|
||||
"strategies\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
name = argv[1];
|
||||
while(name[0] != '\0') {
|
||||
for(i = 0; strategy[i].name; i++) {
|
||||
int n = strlen(strategy[i].name);
|
||||
if((strncmp(name, strategy[i].name, n) == 0) &&
|
||||
(name[n] == '\0' ||
|
||||
name[n] == ',')) {
|
||||
if(strategy[i].selected == 0) {
|
||||
strategy[i].selected = 1;
|
||||
strategy_count++;
|
||||
}
|
||||
name += name[n] == ',' ? n + 1 : n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(strategy[i].name == NULL) {
|
||||
fprintf(stderr, "gzip: -Xstrategy unrecognised "
|
||||
"strategy\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
failed:
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after all options have been parsed.
|
||||
* It is used to do post-processing on the compressor options using
|
||||
* values that were not expected to be known at option parse time.
|
||||
*
|
||||
* This function returns 0 on successful post processing, or
|
||||
* -1 on error
|
||||
*/
|
||||
static int gzip_options_post(int block_size)
|
||||
{
|
||||
if(strategy_count == 1 && strategy[0].selected) {
|
||||
strategy_count = 0;
|
||||
strategy[0].selected = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*
|
||||
*/
|
||||
static void *gzip_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct gzip_comp_opts comp_opts;
|
||||
int i, strategies = 0;
|
||||
|
||||
/*
|
||||
* If default compression options of:
|
||||
* compression-level: 8 and
|
||||
* window-size: 15 and
|
||||
* strategy_count == 0 then
|
||||
* don't store a compression options structure (this is compatible
|
||||
* with the legacy implementation of GZIP for Squashfs)
|
||||
*/
|
||||
if(compression_level == GZIP_DEFAULT_COMPRESSION_LEVEL &&
|
||||
window_size == GZIP_DEFAULT_WINDOW_SIZE &&
|
||||
strategy_count == 0)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; strategy[i].name; i++)
|
||||
strategies |= strategy[i].selected << i;
|
||||
|
||||
comp_opts.compression_level = compression_level;
|
||||
comp_opts.window_size = window_size;
|
||||
comp_opts.strategy = strategies;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int gzip_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct gzip_comp_opts *comp_opts = buffer;
|
||||
int i;
|
||||
|
||||
if(size == 0) {
|
||||
/* Set default values */
|
||||
compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL;
|
||||
window_size = GZIP_DEFAULT_WINDOW_SIZE;
|
||||
strategy_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "gzip: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
compression_level = comp_opts->compression_level;
|
||||
|
||||
if(comp_opts->window_size < 8 ||
|
||||
comp_opts->window_size > 15) {
|
||||
fprintf(stderr, "gzip: bad window size in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
window_size = comp_opts->window_size;
|
||||
|
||||
strategy_count = 0;
|
||||
for(i = 0; strategy[i].name; i++) {
|
||||
if((comp_opts->strategy >> i) & 1) {
|
||||
strategy[i].selected = 1;
|
||||
strategy_count ++;
|
||||
} else
|
||||
strategy[i].selected = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "gzip: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void gzip_display_options(void *buffer, int size)
|
||||
{
|
||||
struct gzip_comp_opts *comp_opts = buffer;
|
||||
int i, printed;
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "gzip: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
printf("\tcompression-level %d\n", comp_opts->compression_level);
|
||||
|
||||
if(comp_opts->window_size < 8 ||
|
||||
comp_opts->window_size > 15) {
|
||||
fprintf(stderr, "gzip: bad window size in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
printf("\twindow-size %d\n", comp_opts->window_size);
|
||||
|
||||
for(i = 0, printed = 0; strategy[i].name; i++) {
|
||||
if((comp_opts->strategy >> i) & 1) {
|
||||
if(printed)
|
||||
printf(", ");
|
||||
else
|
||||
printf("\tStrategies selected: ");
|
||||
printf("%s", strategy[i].name);
|
||||
printed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!printed)
|
||||
printf("\tStrategies selected: default\n");
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "gzip: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to initialise the
|
||||
* compressor, before compress() is called.
|
||||
*
|
||||
* This function returns 0 on success, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int gzip_init(void **strm, int block_size, int datablock)
|
||||
{
|
||||
int i, j, res;
|
||||
struct gzip_stream *stream;
|
||||
|
||||
if(!datablock || !strategy_count) {
|
||||
stream = malloc(sizeof(*stream) + sizeof(struct gzip_strategy));
|
||||
if(stream == NULL)
|
||||
goto failed;
|
||||
|
||||
stream->strategies = 1;
|
||||
stream->strategy[0].strategy = Z_DEFAULT_STRATEGY;
|
||||
} else {
|
||||
stream = malloc(sizeof(*stream) +
|
||||
sizeof(struct gzip_strategy) * strategy_count);
|
||||
if(stream == NULL)
|
||||
goto failed;
|
||||
|
||||
memset(stream->strategy, 0, sizeof(struct gzip_strategy) *
|
||||
strategy_count);
|
||||
|
||||
stream->strategies = strategy_count;
|
||||
|
||||
for(i = 0, j = 0; strategy[i].name; i++) {
|
||||
if(!strategy[i].selected)
|
||||
continue;
|
||||
|
||||
stream->strategy[j].strategy = strategy[i].strategy;
|
||||
if(j) {
|
||||
stream->strategy[j].buffer = malloc(block_size);
|
||||
if(stream->strategy[j].buffer == NULL)
|
||||
goto failed2;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
stream->stream.zalloc = Z_NULL;
|
||||
stream->stream.zfree = Z_NULL;
|
||||
stream->stream.opaque = 0;
|
||||
|
||||
res = deflateInit2(&stream->stream, compression_level, Z_DEFLATED,
|
||||
window_size, 8, stream->strategy[0].strategy);
|
||||
if(res != Z_OK)
|
||||
goto failed2;
|
||||
|
||||
*strm = stream;
|
||||
return 0;
|
||||
|
||||
failed2:
|
||||
for(i = 1; i < stream->strategies; i++)
|
||||
free(stream->strategy[i].buffer);
|
||||
free(stream);
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int gzip_compress(void *strm, void *d, void *s, int size, int block_size,
|
||||
int *error)
|
||||
{
|
||||
int i, res;
|
||||
struct gzip_stream *stream = strm;
|
||||
struct gzip_strategy *selected = NULL;
|
||||
|
||||
stream->strategy[0].buffer = d;
|
||||
|
||||
for(i = 0; i < stream->strategies; i++) {
|
||||
struct gzip_strategy *strategy = &stream->strategy[i];
|
||||
|
||||
res = deflateReset(&stream->stream);
|
||||
if(res != Z_OK)
|
||||
goto failed;
|
||||
|
||||
stream->stream.next_in = s;
|
||||
stream->stream.avail_in = size;
|
||||
stream->stream.next_out = strategy->buffer;
|
||||
stream->stream.avail_out = block_size;
|
||||
|
||||
if(stream->strategies > 1) {
|
||||
res = deflateParams(&stream->stream,
|
||||
compression_level, strategy->strategy);
|
||||
if(res != Z_OK)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
res = deflate(&stream->stream, Z_FINISH);
|
||||
strategy->length = stream->stream.total_out;
|
||||
if(res == Z_STREAM_END) {
|
||||
if(!selected || selected->length > strategy->length)
|
||||
selected = strategy;
|
||||
} else if(res != Z_OK)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(!selected)
|
||||
/*
|
||||
* Output buffer overflow. Return out of buffer space
|
||||
*/
|
||||
return 0;
|
||||
|
||||
if(selected->buffer != d)
|
||||
memcpy(d, selected->buffer, selected->length);
|
||||
|
||||
return (int) selected->length;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* All other errors return failure, with the compressor
|
||||
* specific error code in *error
|
||||
*/
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int gzip_uncompress(void *d, void *s, int size, int outsize, int *error)
|
||||
{
|
||||
int res;
|
||||
unsigned long bytes = outsize;
|
||||
|
||||
res = uncompress(d, &bytes, s, size);
|
||||
|
||||
if(res == Z_OK)
|
||||
return (int) bytes;
|
||||
else {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gzip_usage()
|
||||
{
|
||||
fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
|
||||
fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
|
||||
"%d)\n", GZIP_DEFAULT_COMPRESSION_LEVEL);
|
||||
fprintf(stderr, "\t -Xwindow-size <window-size>\n");
|
||||
fprintf(stderr, "\t\t<window-size> should be 8 .. 15 (default "
|
||||
"%d)\n", GZIP_DEFAULT_WINDOW_SIZE);
|
||||
fprintf(stderr, "\t -Xstrategy strategy1,strategy2,...,strategyN\n");
|
||||
fprintf(stderr, "\t\tCompress using strategy1,strategy2,...,strategyN"
|
||||
" in turn\n");
|
||||
fprintf(stderr, "\t\tand choose the best compression.\n");
|
||||
fprintf(stderr, "\t\tAvailable strategies: default, filtered, "
|
||||
"huffman_only,\n\t\trun_length_encoded and fixed\n");
|
||||
}
|
||||
|
||||
|
||||
struct compressor gzip_comp_ops = {
|
||||
.init = gzip_init,
|
||||
.compress = gzip_compress,
|
||||
.uncompress = gzip_uncompress,
|
||||
.options = gzip_options,
|
||||
.options_post = gzip_options_post,
|
||||
.dump_options = gzip_dump_options,
|
||||
.extract_options = gzip_extract_options,
|
||||
.display_options = gzip_display_options,
|
||||
.usage = gzip_usage,
|
||||
.id = ZLIB_COMPRESSION,
|
||||
.name = "gzip",
|
||||
.supported = 1
|
||||
};
|
75
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.h
Normal file
75
SQUASHFS/squashfs-tools-4.4/squashfs-tools/gzip_wrapper.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
#ifndef GZIP_WRAPPER_H
|
||||
#define GZIP_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* gzip_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le16(unsigned short);
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->compression_level = inswap_le32((s)->compression_level); \
|
||||
(s)->window_size = inswap_le16((s)->window_size); \
|
||||
(s)->strategy = inswap_le16((s)->strategy); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/* Default compression */
|
||||
#define GZIP_DEFAULT_COMPRESSION_LEVEL 9
|
||||
#define GZIP_DEFAULT_WINDOW_SIZE 15
|
||||
|
||||
struct gzip_comp_opts {
|
||||
int compression_level;
|
||||
short window_size;
|
||||
short strategy;
|
||||
};
|
||||
|
||||
struct strategy {
|
||||
char *name;
|
||||
int strategy;
|
||||
int selected;
|
||||
};
|
||||
|
||||
struct gzip_strategy {
|
||||
int strategy;
|
||||
int length;
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
struct gzip_stream {
|
||||
z_stream stream;
|
||||
int strategies;
|
||||
struct gzip_strategy strategy[0];
|
||||
};
|
||||
#endif
|
191
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.c
Normal file
191
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.c
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* info.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
#include "caches-queues-lists.h"
|
||||
|
||||
static int silent = 0;
|
||||
static struct dir_ent *ent = NULL;
|
||||
|
||||
pthread_t info_thread;
|
||||
|
||||
|
||||
void disable_info()
|
||||
{
|
||||
ent = NULL;
|
||||
}
|
||||
|
||||
|
||||
void update_info(struct dir_ent *dir_ent)
|
||||
{
|
||||
ent = dir_ent;
|
||||
}
|
||||
|
||||
|
||||
void print_filename()
|
||||
{
|
||||
struct dir_ent *dir_ent = ent;
|
||||
|
||||
if(dir_ent == NULL)
|
||||
return;
|
||||
|
||||
if(dir_ent->our_dir->subpath[0] != '\0')
|
||||
INFO("%s/%s\n", dir_ent->our_dir->subpath, dir_ent->name);
|
||||
else
|
||||
INFO("/%s\n", dir_ent->name);
|
||||
}
|
||||
|
||||
|
||||
void dump_state()
|
||||
{
|
||||
disable_progress_bar();
|
||||
|
||||
printf("Queue and Cache status dump\n");
|
||||
printf("===========================\n");
|
||||
|
||||
printf("file buffer queue (reader thread -> deflate thread(s))\n");
|
||||
dump_queue(to_deflate);
|
||||
|
||||
printf("uncompressed fragment queue (reader thread -> fragment"
|
||||
" thread(s))\n");
|
||||
dump_queue(to_process_frag);
|
||||
|
||||
printf("processed fragment queue (fragment thread(s) -> main"
|
||||
" thread)\n");
|
||||
dump_seq_queue(to_main, 1);
|
||||
|
||||
printf("compressed block queue (deflate thread(s) -> main thread)\n");
|
||||
dump_seq_queue(to_main, 0);
|
||||
|
||||
printf("uncompressed packed fragment queue (main thread -> fragment"
|
||||
" deflate thread(s))\n");
|
||||
dump_queue(to_frag);
|
||||
|
||||
if(!reproducible) {
|
||||
printf("locked frag queue (compressed frags waiting while multi-block"
|
||||
" file is written)\n");
|
||||
dump_queue(locked_fragment);
|
||||
|
||||
printf("compressed block queue (main & fragment deflate threads(s) ->"
|
||||
" writer thread)\n");
|
||||
dump_queue(to_writer);
|
||||
} else {
|
||||
printf("compressed fragment queue (fragment deflate threads(s) ->"
|
||||
"fragment order thread)\n");
|
||||
|
||||
dump_seq_queue(to_order, 0);
|
||||
|
||||
printf("compressed block queue (main & fragment order threads ->"
|
||||
" writer thread)\n");
|
||||
dump_queue(to_writer);
|
||||
}
|
||||
|
||||
printf("read cache (uncompressed blocks read by reader thread)\n");
|
||||
dump_cache(reader_buffer);
|
||||
|
||||
printf("block write cache (compressed blocks waiting for the writer"
|
||||
" thread)\n");
|
||||
dump_cache(bwriter_buffer);
|
||||
printf("fragment write cache (compressed fragments waiting for the"
|
||||
" writer thread)\n");
|
||||
dump_cache(fwriter_buffer);
|
||||
|
||||
printf("fragment cache (frags waiting to be compressed by fragment"
|
||||
" deflate thread(s))\n");
|
||||
dump_cache(fragment_buffer);
|
||||
|
||||
printf("fragment reserve cache (avoids pipeline stall if frag cache"
|
||||
" full in dup check)\n");
|
||||
dump_cache(reserve_cache);
|
||||
|
||||
enable_progress_bar();
|
||||
}
|
||||
|
||||
|
||||
void *info_thrd(void *arg)
|
||||
{
|
||||
sigset_t sigmask;
|
||||
struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
|
||||
int sig, waiting = 0;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGQUIT);
|
||||
sigaddset(&sigmask, SIGHUP);
|
||||
|
||||
while(1) {
|
||||
if(waiting)
|
||||
sig = sigtimedwait(&sigmask, NULL, ×pec);
|
||||
else
|
||||
sig = sigwaitinfo(&sigmask, NULL);
|
||||
|
||||
if(sig == -1) {
|
||||
switch(errno) {
|
||||
case EAGAIN:
|
||||
/* interval timed out */
|
||||
waiting = 0;
|
||||
/* FALLTHROUGH */
|
||||
case EINTR:
|
||||
/* if waiting, the wait will be longer, but
|
||||
that's OK */
|
||||
continue;
|
||||
default:
|
||||
BAD_ERROR("sigtimedwait/sigwaitinfo failed "
|
||||
"because %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if(sig == SIGQUIT && !waiting) {
|
||||
print_filename();
|
||||
|
||||
/* set one second interval period, if ^\ received
|
||||
within then, dump queue and cache status */
|
||||
waiting = 1;
|
||||
} else
|
||||
dump_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_info()
|
||||
{
|
||||
pthread_create(&info_thread, NULL, info_thrd, NULL);
|
||||
}
|
30
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.h
Normal file
30
SQUASHFS/squashfs-tools-4.4/squashfs-tools/info.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef INFO_H
|
||||
#define INFO_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* info.h
|
||||
*/
|
||||
|
||||
extern void disable_info();
|
||||
extern void update_info(struct dir_ent *);
|
||||
extern void init_info();
|
||||
#endif
|
286
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.c
Normal file
286
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lz4_wrapper.c
|
||||
*
|
||||
* Support for LZ4 compression http://fastcompression.blogspot.com/p/lz4.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <lz4.h>
|
||||
#include <lz4hc.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "lz4_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
/* LZ4 1.7.0 introduced new functions, and since r131,
|
||||
* the older functions produce deprecated warnings.
|
||||
*
|
||||
* There are still too many distros using older versions
|
||||
* to switch to the newer functions, but, the deprecated
|
||||
* functions may completely disappear. This is a mess.
|
||||
*
|
||||
* Support both by checking the library version and
|
||||
* using shadow definitions
|
||||
*/
|
||||
|
||||
/* Earlier (but > 1.7.0) versions don't define this */
|
||||
#ifndef LZ4HC_CLEVEL_MAX
|
||||
#define LZ4HC_CLEVEL_MAX 12
|
||||
#endif
|
||||
|
||||
#if LZ4_VERSION_NUMBER >= 10700
|
||||
#define COMPRESS(src, dest, size, max) LZ4_compress_default(src, dest, size, max)
|
||||
#define COMPRESS_HC(src, dest, size, max) LZ4_compress_HC(src, dest, size, max, LZ4HC_CLEVEL_MAX)
|
||||
#else
|
||||
#define COMPRESS(src, dest, size, max) LZ4_compress_limitedOutput(src, dest, size, max)
|
||||
#define COMPRESS_HC(src, dest, size, max) LZ4_compressHC_limitedOutput(src, dest, size, max)
|
||||
#endif
|
||||
|
||||
static int hc = 0;
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The lz4_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int lz4_options(char *argv[], int argc)
|
||||
{
|
||||
if(strcmp(argv[0], "-Xhc") == 0) {
|
||||
hc = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*
|
||||
* Currently LZ4 always returns a comp_opts structure, with
|
||||
* the version indicating LZ4_LEGACY stream fomat. This is to
|
||||
* easily accomodate changes in the kernel code to different
|
||||
* stream formats
|
||||
*/
|
||||
static void *lz4_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct lz4_comp_opts comp_opts;
|
||||
|
||||
comp_opts.version = LZ4_LEGACY;
|
||||
comp_opts.flags = hc ? LZ4_HC : 0;
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int lz4_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct lz4_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* we expect the stream format to be LZ4_LEGACY */
|
||||
if(comp_opts->version != LZ4_LEGACY) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 version\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check compression flags, currently only LZ4_HC ("high compression")
|
||||
* can be set.
|
||||
*/
|
||||
if(comp_opts->flags == LZ4_HC)
|
||||
hc = 1;
|
||||
else if(comp_opts->flags != 0) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 flags\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lz4: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for unsquashfs.
|
||||
* Its purpose is to check that the compression options are
|
||||
* understood by this version of LZ4.
|
||||
*
|
||||
* This is important for LZ4 because the format understood by the
|
||||
* Linux kernel may change from the already obsolete legacy format
|
||||
* currently supported.
|
||||
*
|
||||
* If this does happen, then this version of LZ4 will not be able to decode
|
||||
* the newer format. So we need to check for this.
|
||||
*
|
||||
* This function returns 0 on sucessful checking of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int lz4_check_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct lz4_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* we expect the stream format to be LZ4_LEGACY */
|
||||
if(comp_opts->version != LZ4_LEGACY) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 version\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lz4: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void lz4_display_options(void *buffer, int size)
|
||||
{
|
||||
struct lz4_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* check passed comp opts struct is of the correct length */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* we expect the stream format to be LZ4_LEGACY */
|
||||
if(comp_opts->version != LZ4_LEGACY) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 version\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check compression flags, currently only LZ4_HC ("high compression")
|
||||
* can be set.
|
||||
*/
|
||||
if(comp_opts->flags & ~LZ4_FLAGS_MASK) {
|
||||
fprintf(stderr, "lz4: unknown LZ4 flags\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(comp_opts->flags & LZ4_HC)
|
||||
printf("\tHigh Compression option specified (-Xhc)\n");
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lz4: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
static int lz4_compress(void *strm, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lz4_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
int res = LZ4_decompress_safe(src, dest, size, outsize);
|
||||
if(res < 0) {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void lz4_usage()
|
||||
{
|
||||
fprintf(stderr, "\t -Xhc\n");
|
||||
fprintf(stderr, "\t\tCompress using LZ4 High Compression\n");
|
||||
}
|
||||
|
||||
|
||||
struct compressor lz4_comp_ops = {
|
||||
.compress = lz4_compress,
|
||||
.uncompress = lz4_uncompress,
|
||||
.options = lz4_options,
|
||||
.dump_options = lz4_dump_options,
|
||||
.extract_options = lz4_extract_options,
|
||||
.check_options = lz4_check_options,
|
||||
.display_options = lz4_display_options,
|
||||
.usage = lz4_usage,
|
||||
.id = LZ4_COMPRESSION,
|
||||
.name = "lz4",
|
||||
.supported = 1
|
||||
};
|
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.h
Normal file
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lz4_wrapper.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef LZ4_WRAPPER_H
|
||||
#define LZ4_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lz4_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->version = inswap_le32((s)->version); \
|
||||
(s)->flags = inswap_le32((s)->flags); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the various stream formats recognised.
|
||||
* Currently omly legacy stream format is supported by the
|
||||
* kernel
|
||||
*/
|
||||
#define LZ4_LEGACY 1
|
||||
#define LZ4_FLAGS_MASK 1
|
||||
|
||||
/* Define the compression flags recognised. */
|
||||
#define LZ4_HC 1
|
||||
|
||||
struct lz4_comp_opts {
|
||||
int version;
|
||||
int flags;
|
||||
};
|
||||
#endif
|
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_wrapper.c
Normal file
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_wrapper.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzma_wrapper.c
|
||||
*
|
||||
* Support for LZMA1 compression using LZMA SDK (4.65 used in
|
||||
* development, other versions may work) http://www.7-zip.org/sdk.html
|
||||
*/
|
||||
|
||||
#include <LzmaLib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "compressor.h"
|
||||
|
||||
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
|
||||
|
||||
static int lzma_compress(void *strm, void *dest, void *src, int size, int block_size,
|
||||
int *error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lzma_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
size_t outlen, inlen = size - LZMA_HEADER_SIZE;
|
||||
int res;
|
||||
|
||||
outlen = s[LZMA_PROPS_SIZE] |
|
||||
(s[LZMA_PROPS_SIZE + 1] << 8) |
|
||||
(s[LZMA_PROPS_SIZE + 2] << 16) |
|
||||
(s[LZMA_PROPS_SIZE + 3] << 24);
|
||||
|
||||
if(outlen > outsize) {
|
||||
*error = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = LzmaUncompress(dest, &outlen, src + LZMA_HEADER_SIZE, &inlen, src,
|
||||
LZMA_PROPS_SIZE);
|
||||
|
||||
if(res == SZ_OK)
|
||||
return outlen;
|
||||
else {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct compressor lzma_comp_ops = {
|
||||
.init = NULL,
|
||||
.compress = lzma_compress,
|
||||
.uncompress = lzma_uncompress,
|
||||
.options = NULL,
|
||||
.usage = NULL,
|
||||
.id = LZMA_COMPRESSION,
|
||||
.name = "lzma",
|
||||
.supported = 1
|
||||
};
|
||||
|
163
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_xz_wrapper.c
Normal file
163
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzma_xz_wrapper.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzma_xz_wrapper.c
|
||||
*
|
||||
* Support for LZMA1 compression using XZ Utils liblzma http://tukaani.org/xz/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lzma.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "compressor.h"
|
||||
|
||||
#define LZMA_PROPS_SIZE 5
|
||||
#define LZMA_UNCOMP_SIZE 8
|
||||
#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNCOMP_SIZE)
|
||||
|
||||
#define LZMA_OPTIONS 5
|
||||
#define MEMLIMIT (32 * 1024 * 1024)
|
||||
|
||||
static int lzma_compress(void *dummy, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
unsigned char *d = (unsigned char *) dest;
|
||||
lzma_options_lzma opt;
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
int res;
|
||||
|
||||
lzma_lzma_preset(&opt, LZMA_OPTIONS);
|
||||
opt.dict_size = block_size;
|
||||
|
||||
res = lzma_alone_encoder(&strm, &opt);
|
||||
if(res != LZMA_OK) {
|
||||
lzma_end(&strm);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
strm.next_out = dest;
|
||||
strm.avail_out = block_size;
|
||||
strm.next_in = src;
|
||||
strm.avail_in = size;
|
||||
|
||||
res = lzma_code(&strm, LZMA_FINISH);
|
||||
lzma_end(&strm);
|
||||
|
||||
if(res == LZMA_STREAM_END) {
|
||||
/*
|
||||
* Fill in the 8 byte little endian uncompressed size field in
|
||||
* the LZMA header. 8 bytes is excessively large for squashfs
|
||||
* but this is the standard LZMA header and which is expected by
|
||||
* the kernel code
|
||||
*/
|
||||
|
||||
d[LZMA_PROPS_SIZE] = size & 255;
|
||||
d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255;
|
||||
d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255;
|
||||
d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255;
|
||||
d[LZMA_PROPS_SIZE + 4] = 0;
|
||||
d[LZMA_PROPS_SIZE + 5] = 0;
|
||||
d[LZMA_PROPS_SIZE + 6] = 0;
|
||||
d[LZMA_PROPS_SIZE + 7] = 0;
|
||||
|
||||
return (int) strm.total_out;
|
||||
}
|
||||
|
||||
if(res == LZMA_OK)
|
||||
/*
|
||||
* Output buffer overflow. Return out of buffer space
|
||||
*/
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* All other errors return failure, with the compressor
|
||||
* specific error code in *error
|
||||
*/
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int lzma_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
int uncompressed_size = 0, res;
|
||||
unsigned char lzma_header[LZMA_HEADER_SIZE];
|
||||
|
||||
res = lzma_alone_decoder(&strm, MEMLIMIT);
|
||||
if(res != LZMA_OK) {
|
||||
lzma_end(&strm);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memcpy(lzma_header, src, LZMA_HEADER_SIZE);
|
||||
uncompressed_size = lzma_header[LZMA_PROPS_SIZE] |
|
||||
(lzma_header[LZMA_PROPS_SIZE + 1] << 8) |
|
||||
(lzma_header[LZMA_PROPS_SIZE + 2] << 16) |
|
||||
(lzma_header[LZMA_PROPS_SIZE + 3] << 24);
|
||||
|
||||
if(uncompressed_size > outsize) {
|
||||
res = 0;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memset(lzma_header + LZMA_PROPS_SIZE, 255, LZMA_UNCOMP_SIZE);
|
||||
|
||||
strm.next_out = dest;
|
||||
strm.avail_out = outsize;
|
||||
strm.next_in = lzma_header;
|
||||
strm.avail_in = LZMA_HEADER_SIZE;
|
||||
|
||||
res = lzma_code(&strm, LZMA_RUN);
|
||||
|
||||
if(res != LZMA_OK || strm.avail_in != 0) {
|
||||
lzma_end(&strm);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
strm.next_in = src + LZMA_HEADER_SIZE;
|
||||
strm.avail_in = size - LZMA_HEADER_SIZE;
|
||||
|
||||
res = lzma_code(&strm, LZMA_FINISH);
|
||||
lzma_end(&strm);
|
||||
|
||||
if(res == LZMA_STREAM_END || (res == LZMA_OK &&
|
||||
strm.total_out >= uncompressed_size && strm.avail_in == 0))
|
||||
return uncompressed_size;
|
||||
|
||||
failed:
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct compressor lzma_comp_ops = {
|
||||
.init = NULL,
|
||||
.compress = lzma_compress,
|
||||
.uncompress = lzma_uncompress,
|
||||
.options = NULL,
|
||||
.usage = NULL,
|
||||
.id = LZMA_COMPRESSION,
|
||||
.name = "lzma",
|
||||
.supported = 1
|
||||
};
|
||||
|
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.c
Normal file
365
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.c
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzo_wrapper.c
|
||||
*
|
||||
* Support for LZO compression http://www.oberhumer.com/opensource/lzo
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <lzo/lzoconf.h>
|
||||
#include <lzo/lzo1x.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "lzo_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
static struct lzo_algorithm lzo[] = {
|
||||
{ "lzo1x_1", LZO1X_1_MEM_COMPRESS, lzo1x_1_compress },
|
||||
{ "lzo1x_1_11", LZO1X_1_11_MEM_COMPRESS, lzo1x_1_11_compress },
|
||||
{ "lzo1x_1_12", LZO1X_1_12_MEM_COMPRESS, lzo1x_1_12_compress },
|
||||
{ "lzo1x_1_15", LZO1X_1_15_MEM_COMPRESS, lzo1x_1_15_compress },
|
||||
{ "lzo1x_999", LZO1X_999_MEM_COMPRESS, lzo1x_999_wrapper },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
/* default LZO compression algorithm and compression level */
|
||||
static int algorithm = SQUASHFS_LZO1X_999;
|
||||
static int compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
|
||||
|
||||
/* user specified compression level */
|
||||
static int user_comp_level = -1;
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The lzo_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int lzo_options(char *argv[], int argc)
|
||||
{
|
||||
(void)argv;
|
||||
(void)argc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after all options have been parsed.
|
||||
* It is used to do post-processing on the compressor options using
|
||||
* values that were not expected to be known at option parse time.
|
||||
*
|
||||
* In this case the LZO algorithm may not be known until after the
|
||||
* compression level has been set (-Xalgorithm used after -Xcompression-level)
|
||||
*
|
||||
* This function returns 0 on successful post processing, or
|
||||
* -1 on error
|
||||
*/
|
||||
static int lzo_options_post(int block_size)
|
||||
{
|
||||
/*
|
||||
* Use of compression level only makes sense for
|
||||
* LZO1X_999 algorithm
|
||||
*/
|
||||
if(user_comp_level != -1) {
|
||||
if(algorithm != SQUASHFS_LZO1X_999) {
|
||||
fprintf(stderr, "lzo: -Xcompression-level not "
|
||||
"supported by selected %s algorithm\n",
|
||||
lzo[algorithm].name);
|
||||
fprintf(stderr, "lzo: -Xcompression-level is only "
|
||||
"applicable for the lzo1x_999 algorithm\n");
|
||||
goto failed;
|
||||
}
|
||||
compression_level = user_comp_level;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*
|
||||
*/
|
||||
static void *lzo_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct lzo_comp_opts comp_opts;
|
||||
|
||||
/*
|
||||
* If default compression options of SQUASHFS_LZO1X_999 and
|
||||
* compression level of SQUASHFS_LZO1X_999_COMP_DEFAULT then
|
||||
* don't store a compression options structure (this is compatible
|
||||
* with the legacy implementation of LZO for Squashfs)
|
||||
*/
|
||||
if(algorithm == SQUASHFS_LZO1X_999 &&
|
||||
compression_level == SQUASHFS_LZO1X_999_COMP_DEFAULT)
|
||||
return NULL;
|
||||
|
||||
comp_opts.algorithm = algorithm;
|
||||
comp_opts.compression_level = algorithm == SQUASHFS_LZO1X_999 ?
|
||||
compression_level : 0;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int lzo_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct lzo_comp_opts *comp_opts = buffer;
|
||||
|
||||
if(size == 0) {
|
||||
/* Set default values */
|
||||
algorithm = SQUASHFS_LZO1X_999;
|
||||
compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
switch(comp_opts->algorithm) {
|
||||
case SQUASHFS_LZO1X_1:
|
||||
case SQUASHFS_LZO1X_1_11:
|
||||
case SQUASHFS_LZO1X_1_12:
|
||||
case SQUASHFS_LZO1X_1_15:
|
||||
if(comp_opts->compression_level != 0) {
|
||||
fprintf(stderr, "lzo: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
case SQUASHFS_LZO1X_999:
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "lzo: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
compression_level = comp_opts->compression_level;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "lzo: bad algorithm in compression options "
|
||||
"structure\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
algorithm = comp_opts->algorithm;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lzo: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void lzo_display_options(void *buffer, int size)
|
||||
{
|
||||
struct lzo_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if(size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
/* Check comp_opts structure for correctness */
|
||||
switch(comp_opts->algorithm) {
|
||||
case SQUASHFS_LZO1X_1:
|
||||
case SQUASHFS_LZO1X_1_11:
|
||||
case SQUASHFS_LZO1X_1_12:
|
||||
case SQUASHFS_LZO1X_1_15:
|
||||
printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
|
||||
break;
|
||||
case SQUASHFS_LZO1X_999:
|
||||
if(comp_opts->compression_level < 1 ||
|
||||
comp_opts->compression_level > 9) {
|
||||
fprintf(stderr, "lzo: bad compression level in "
|
||||
"compression options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name);
|
||||
printf("\tcompression level %d\n",
|
||||
comp_opts->compression_level);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "lzo: bad algorithm in compression options "
|
||||
"structure\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "lzo: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to initialise the
|
||||
* compressor, before compress() is called.
|
||||
*
|
||||
* This function returns 0 on success, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int squashfs_lzo_init(void **strm, int block_size, int datablock)
|
||||
{
|
||||
struct lzo_stream *stream;
|
||||
|
||||
stream = *strm = malloc(sizeof(struct lzo_stream));
|
||||
if(stream == NULL)
|
||||
goto failed;
|
||||
|
||||
stream->workspace = malloc(lzo[algorithm].size);
|
||||
if(stream->workspace == NULL)
|
||||
goto failed2;
|
||||
|
||||
stream->buffer = malloc(LZO_MAX_EXPANSION(block_size));
|
||||
if(stream->buffer != NULL)
|
||||
return 0;
|
||||
|
||||
free(stream->workspace);
|
||||
failed2:
|
||||
free(stream);
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int lzo_compress(void *strm, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lzo_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
int res;
|
||||
lzo_uint outlen = outsize;
|
||||
|
||||
res = lzo1x_decompress_safe(src, size, dest, &outlen, NULL);
|
||||
if(res != LZO_E_OK) {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
|
||||
static void lzo_usage()
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "\t -Xalgorithm <algorithm>\n");
|
||||
fprintf(stderr, "\t\tWhere <algorithm> is one of:\n");
|
||||
|
||||
for(i = 0; lzo[i].name; i++)
|
||||
fprintf(stderr, "\t\t\t%s%s\n", lzo[i].name,
|
||||
i == SQUASHFS_LZO1X_999 ? " (default)" : "");
|
||||
|
||||
fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
|
||||
fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default "
|
||||
"%d)\n", SQUASHFS_LZO1X_999_COMP_DEFAULT);
|
||||
fprintf(stderr, "\t\tOnly applies to lzo1x_999 algorithm\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function for lzo1x_999 compression algorithm.
|
||||
* All other lzo1x_xxx compressors do not take a compression level,
|
||||
* so we need to wrap lzo1x_999 to pass the compression level which
|
||||
* is applicable to it
|
||||
*/
|
||||
int lzo1x_999_wrapper(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst,
|
||||
lzo_uintp compsize, lzo_voidp workspace)
|
||||
{
|
||||
return lzo1x_999_compress_level(src, src_len, dst, compsize,
|
||||
workspace, NULL, 0, 0, compression_level);
|
||||
}
|
||||
|
||||
|
||||
struct compressor lzo_comp_ops = {
|
||||
.init = squashfs_lzo_init,
|
||||
.compress = lzo_compress,
|
||||
.uncompress = lzo_uncompress,
|
||||
.options = lzo_options,
|
||||
.options_post = lzo_options_post,
|
||||
.dump_options = lzo_dump_options,
|
||||
.extract_options = lzo_extract_options,
|
||||
.display_options = lzo_display_options,
|
||||
.usage = lzo_usage,
|
||||
.id = LZO_COMPRESSION,
|
||||
.name = "lzo",
|
||||
.supported = 1
|
||||
};
|
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.h
Normal file
78
SQUASHFS/squashfs-tools-4.4/squashfs-tools/lzo_wrapper.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef LZO_WRAPPER_H
|
||||
#define LZO_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* lzo_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->algorithm = inswap_le32((s)->algorithm); \
|
||||
(s)->compression_level = inswap_le32((s)->compression_level); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/* Define the compression flags recognised. */
|
||||
#define SQUASHFS_LZO1X_1 0
|
||||
#define SQUASHFS_LZO1X_1_11 1
|
||||
#define SQUASHFS_LZO1X_1_12 2
|
||||
#define SQUASHFS_LZO1X_1_15 3
|
||||
#define SQUASHFS_LZO1X_999 4
|
||||
|
||||
/* Default compression level used by SQUASHFS_LZO1X_999 */
|
||||
#define SQUASHFS_LZO1X_999_COMP_DEFAULT 8
|
||||
|
||||
struct lzo_comp_opts {
|
||||
int algorithm;
|
||||
int compression_level;
|
||||
};
|
||||
|
||||
struct lzo_algorithm {
|
||||
char *name;
|
||||
int size;
|
||||
int (*compress) (const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
|
||||
lzo_voidp);
|
||||
};
|
||||
|
||||
struct lzo_stream {
|
||||
void *workspace;
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
#define LZO_MAX_EXPANSION(size) (size + (size / 16) + 64 + 3)
|
||||
|
||||
int lzo1x_999_wrapper(const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp,
|
||||
lzo_voidp);
|
||||
|
||||
#endif
|
6372
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.c
Normal file
6372
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.c
Normal file
File diff suppressed because it is too large
Load diff
165
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.h
Normal file
165
SQUASHFS/squashfs-tools-4.4/squashfs-tools/mksquashfs.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
#ifndef MKSQUASHFS_H
|
||||
#define MKSQUASHFS_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
||||
* 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* mksquashfs.h
|
||||
*
|
||||
*/
|
||||
|
||||
struct dir_info {
|
||||
char *pathname;
|
||||
char *subpath;
|
||||
unsigned int count;
|
||||
unsigned int directory_count;
|
||||
int depth;
|
||||
unsigned int excluded;
|
||||
char dir_is_ldir;
|
||||
struct dir_ent *dir_ent;
|
||||
struct dir_ent *list;
|
||||
DIR *linuxdir;
|
||||
};
|
||||
|
||||
struct dir_ent {
|
||||
char *name;
|
||||
char *source_name;
|
||||
char *nonstandard_pathname;
|
||||
struct inode_info *inode;
|
||||
struct dir_info *dir;
|
||||
struct dir_info *our_dir;
|
||||
struct dir_ent *next;
|
||||
};
|
||||
|
||||
struct inode_info {
|
||||
struct stat buf;
|
||||
struct inode_info *next;
|
||||
squashfs_inode inode;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
int pseudo_id;
|
||||
char type;
|
||||
char read;
|
||||
char root_entry;
|
||||
char pseudo_file;
|
||||
char no_fragments;
|
||||
char always_use_fragments;
|
||||
char noD;
|
||||
char noF;
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
/* in memory file info */
|
||||
struct file_info {
|
||||
long long file_size;
|
||||
long long bytes;
|
||||
long long start;
|
||||
unsigned int *block_list;
|
||||
struct file_info *next;
|
||||
struct fragment *fragment;
|
||||
unsigned short checksum;
|
||||
unsigned short fragment_checksum;
|
||||
char have_frag_checksum;
|
||||
char have_checksum;
|
||||
};
|
||||
|
||||
/* fragment block data structures */
|
||||
struct fragment {
|
||||
unsigned int index;
|
||||
int offset;
|
||||
int size;
|
||||
};
|
||||
|
||||
/* in memory uid tables */
|
||||
#define ID_ENTRIES 256
|
||||
#define ID_HASH(id) (id & (ID_ENTRIES - 1))
|
||||
#define ISA_UID 1
|
||||
#define ISA_GID 2
|
||||
|
||||
struct id {
|
||||
unsigned int id;
|
||||
int index;
|
||||
char flags;
|
||||
struct id *next;
|
||||
};
|
||||
|
||||
/* fragment to file mapping used when appending */
|
||||
struct append_file {
|
||||
struct file_info *file;
|
||||
struct append_file *next;
|
||||
};
|
||||
|
||||
#define PSEUDO_FILE_OTHER 1
|
||||
#define PSEUDO_FILE_PROCESS 2
|
||||
|
||||
#define IS_PSEUDO(a) ((a)->pseudo_file)
|
||||
#define IS_PSEUDO_PROCESS(a) ((a)->pseudo_file & PSEUDO_FILE_PROCESS)
|
||||
#define IS_PSEUDO_OTHER(a) ((a)->pseudo_file & PSEUDO_FILE_OTHER)
|
||||
|
||||
/*
|
||||
* Amount of physical memory to use by default, and the default queue
|
||||
* ratios
|
||||
*/
|
||||
#define SQUASHFS_TAKE 4
|
||||
#define SQUASHFS_READQ_MEM 4
|
||||
#define SQUASHFS_BWRITEQ_MEM 4
|
||||
#define SQUASHFS_FWRITEQ_MEM 4
|
||||
|
||||
/*
|
||||
* Lowest amount of physical memory considered viable for Mksquashfs
|
||||
* to run in Mbytes
|
||||
*/
|
||||
#define SQUASHFS_LOWMEM 64
|
||||
|
||||
/* offset of data in compressed metadata blocks (allowing room for
|
||||
* compressed size */
|
||||
#define BLOCK_OFFSET 2
|
||||
|
||||
#ifdef REPRODUCIBLE_DEFAULT
|
||||
#define NOREP_STR
|
||||
#define REP_STR " (default)"
|
||||
#define REP_DEF 1
|
||||
#else
|
||||
#define NOREP_STR " (default)"
|
||||
#define REP_STR
|
||||
#define REP_DEF 0
|
||||
#endif
|
||||
|
||||
extern struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
|
||||
struct cache *bwriter_buffer, *fwriter_buffer;
|
||||
extern struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
|
||||
*to_frag, *locked_fragment, *to_process_frag;
|
||||
extern struct append_file **file_mapping;
|
||||
extern struct seq_queue *to_main, *to_order;
|
||||
extern pthread_mutex_t fragment_mutex, dup_mutex;
|
||||
extern struct squashfs_fragment_entry *fragment_table;
|
||||
extern struct compressor *comp;
|
||||
extern int block_size;
|
||||
extern struct file_info *dupl[];
|
||||
extern int read_fs_bytes(int, long long, int, void *);
|
||||
extern void add_file(long long, long long, long long, unsigned int *, int,
|
||||
unsigned int, int, int);
|
||||
extern struct id *create_id(unsigned int);
|
||||
extern unsigned int get_uid(unsigned int);
|
||||
extern unsigned int get_guid(unsigned int);
|
||||
extern int read_bytes(int, void *, int);
|
||||
extern unsigned short get_checksum_mem(char *, int);
|
||||
extern int reproducible;
|
||||
#endif
|
371
SQUASHFS/squashfs-tools-4.4/squashfs-tools/process_fragments.c
Normal file
371
SQUASHFS/squashfs-tools-4.4/squashfs-tools/process_fragments.c
Normal file
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* process_fragments.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "caches-queues-lists.h"
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
#include "info.h"
|
||||
#include "compressor.h"
|
||||
#include "process_fragments.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
extern struct queue *to_process_frag;
|
||||
extern struct seq_queue *to_main;
|
||||
extern int sparse_files;
|
||||
extern long long start_offset;
|
||||
|
||||
/*
|
||||
* Compute 16 bit BSD checksum over the data, and check for sparseness
|
||||
*/
|
||||
static int checksum_sparse(struct file_buffer *file_buffer)
|
||||
{
|
||||
unsigned char *b = (unsigned char *) file_buffer->data;
|
||||
unsigned short chksum = 0;
|
||||
int bytes = file_buffer->size, sparse = TRUE, value;
|
||||
|
||||
while(bytes --) {
|
||||
chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
|
||||
value = *b++;
|
||||
if(value) {
|
||||
sparse = FALSE;
|
||||
chksum += value;
|
||||
}
|
||||
}
|
||||
|
||||
file_buffer->checksum = chksum;
|
||||
return sparse;
|
||||
}
|
||||
|
||||
|
||||
static int read_filesystem(int fd, long long byte, int bytes, void *buff)
|
||||
{
|
||||
off_t off = byte;
|
||||
|
||||
TRACE("read_filesystem: reading from position 0x%llx, bytes %d\n",
|
||||
byte, bytes);
|
||||
|
||||
if(lseek(fd, start_offset + off, SEEK_SET) == -1) {
|
||||
ERROR("read_filesystem: Lseek on destination failed because %s, "
|
||||
"offset=0x%llx\n", strerror(errno), start_offset + off);
|
||||
return 0;
|
||||
} else if(read_bytes(fd, buff, bytes) < bytes) {
|
||||
ERROR("Read on destination failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct file_buffer *get_fragment(struct fragment *fragment,
|
||||
char *data_buffer, int fd)
|
||||
{
|
||||
struct squashfs_fragment_entry *disk_fragment;
|
||||
struct file_buffer *buffer, *compressed_buffer;
|
||||
long long start_block;
|
||||
int res, size, index = fragment->index;
|
||||
char locked;
|
||||
|
||||
/*
|
||||
* Lookup fragment block in cache.
|
||||
* If the fragment block doesn't exist, then get the compressed version
|
||||
* from the writer cache or off disk, and decompress it.
|
||||
*
|
||||
* This routine has two things which complicate the code:
|
||||
*
|
||||
* 1. Multiple threads can simultaneously lookup/create the
|
||||
* same buffer. This means a buffer needs to be "locked"
|
||||
* when it is being filled in, to prevent other threads from
|
||||
* using it when it is not ready. This is because we now do
|
||||
* fragment duplicate checking in parallel.
|
||||
* 2. We have two caches which need to be checked for the
|
||||
* presence of fragment blocks: the normal fragment cache
|
||||
* and a "reserve" cache. The reserve cache is used to
|
||||
* prevent an unnecessary pipeline stall when the fragment cache
|
||||
* is full of fragments waiting to be compressed.
|
||||
*/
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
|
||||
again:
|
||||
buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
|
||||
if(buffer) {
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
if(locked)
|
||||
/* got a buffer being filled in. Wait for it */
|
||||
cache_wait_unlock(buffer);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* not in fragment cache, is it in the reserve cache? */
|
||||
buffer = cache_lookup_nowait(reserve_cache, index, &locked);
|
||||
if(buffer) {
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
if(locked)
|
||||
/* got a buffer being filled in. Wait for it */
|
||||
cache_wait_unlock(buffer);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* in neither cache, try to get it from the fragment cache */
|
||||
buffer = cache_get_nowait(fragment_buffer, index);
|
||||
if(!buffer) {
|
||||
/*
|
||||
* no room, get it from the reserve cache, this is
|
||||
* dimensioned so it will always have space (no more than
|
||||
* processors + 1 can have an outstanding reserve buffer)
|
||||
*/
|
||||
buffer = cache_get_nowait(reserve_cache, index);
|
||||
if(!buffer) {
|
||||
/* failsafe */
|
||||
ERROR("no space in reserve cache\n");
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
|
||||
compressed_buffer = cache_lookup(fwriter_buffer, index);
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
|
||||
pthread_mutex_lock(&fragment_mutex);
|
||||
disk_fragment = &fragment_table[index];
|
||||
size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
|
||||
start_block = disk_fragment->start_block;
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
|
||||
int error;
|
||||
char *data;
|
||||
|
||||
if(compressed_buffer)
|
||||
data = compressed_buffer->data;
|
||||
else {
|
||||
res = read_filesystem(fd, start_block, size, data_buffer);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read fragment from output"
|
||||
" filesystem\n");
|
||||
BAD_ERROR("Output filesystem corrupted?\n");
|
||||
}
|
||||
data = data_buffer;
|
||||
}
|
||||
|
||||
res = compressor_uncompress(comp, buffer->data, data, size,
|
||||
block_size, &error);
|
||||
if(res == -1)
|
||||
BAD_ERROR("%s uncompress failed with error code %d\n",
|
||||
comp->name, error);
|
||||
} else if(compressed_buffer)
|
||||
memcpy(buffer->data, compressed_buffer->data, size);
|
||||
else {
|
||||
res = read_filesystem(fd, start_block, size, buffer->data);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read fragment from output "
|
||||
"filesystem\n");
|
||||
BAD_ERROR("Output filesystem corrupted?\n");
|
||||
}
|
||||
}
|
||||
|
||||
cache_unlock(buffer);
|
||||
cache_block_put(compressed_buffer);
|
||||
|
||||
finished:
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
struct file_buffer *get_fragment_cksum(struct file_info *file,
|
||||
char *data_buffer, int fd, unsigned short *checksum)
|
||||
{
|
||||
struct file_buffer *frag_buffer;
|
||||
struct append_file *append;
|
||||
int index = file->fragment->index;
|
||||
|
||||
frag_buffer = get_fragment(file->fragment, data_buffer, fd);
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
|
||||
|
||||
for(append = file_mapping[index]; append; append = append->next) {
|
||||
int offset = append->file->fragment->offset;
|
||||
int size = append->file->fragment->size;
|
||||
char *data = frag_buffer->data + offset;
|
||||
unsigned short cksum = get_checksum_mem(data, size);
|
||||
|
||||
if(file == append->file)
|
||||
*checksum = cksum;
|
||||
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
append->file->fragment_checksum = cksum;
|
||||
append->file->have_frag_checksum = TRUE;
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
return frag_buffer;
|
||||
}
|
||||
|
||||
|
||||
void *frag_thrd(void *destination_file)
|
||||
{
|
||||
sigset_t sigmask, old_mask;
|
||||
char *data_buffer;
|
||||
int fd;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGINT);
|
||||
sigaddset(&sigmask, SIGTERM);
|
||||
sigaddset(&sigmask, SIGUSR1);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask);
|
||||
|
||||
fd = open(destination_file, O_RDONLY);
|
||||
if(fd == -1)
|
||||
BAD_ERROR("frag_thrd: can't open destination for reading\n");
|
||||
|
||||
data_buffer = malloc(SQUASHFS_FILE_MAX_SIZE);
|
||||
if(data_buffer == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
|
||||
|
||||
while(1) {
|
||||
struct file_buffer *file_buffer = queue_get(to_process_frag);
|
||||
struct file_buffer *buffer;
|
||||
int sparse = checksum_sparse(file_buffer);
|
||||
struct file_info *dupl_ptr;
|
||||
long long file_size;
|
||||
unsigned short checksum;
|
||||
char flag;
|
||||
int res;
|
||||
|
||||
if(sparse_files && sparse) {
|
||||
file_buffer->c_byte = 0;
|
||||
file_buffer->fragment = FALSE;
|
||||
} else
|
||||
file_buffer->c_byte = file_buffer->size;
|
||||
|
||||
/*
|
||||
* Specutively pull into the fragment cache any fragment blocks
|
||||
* which contain fragments which *this* fragment may be
|
||||
* be a duplicate.
|
||||
*
|
||||
* By ensuring the fragment block is in cache ahead of time
|
||||
* should eliminate the parallelisation stall when the
|
||||
* main thread needs to read the fragment block to do a
|
||||
* duplicate check on it.
|
||||
*
|
||||
* If this is a fragment belonging to a larger file
|
||||
* (with additional blocks) then ignore it. Here we're
|
||||
* interested in the "low hanging fruit" of files which
|
||||
* consist of only a fragment
|
||||
*/
|
||||
if(file_buffer->file_size != file_buffer->size) {
|
||||
seq_queue_put(to_main, file_buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
file_size = file_buffer->file_size;
|
||||
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
dupl_ptr = dupl[DUP_HASH(file_size)];
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
|
||||
file_buffer->dupl_start = dupl_ptr;
|
||||
file_buffer->duplicate = FALSE;
|
||||
|
||||
for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
|
||||
if(file_size != dupl_ptr->file_size ||
|
||||
file_size != dupl_ptr->fragment->size)
|
||||
continue;
|
||||
|
||||
pthread_mutex_lock(&dup_mutex);
|
||||
flag = dupl_ptr->have_frag_checksum;
|
||||
checksum = dupl_ptr->fragment_checksum;
|
||||
pthread_mutex_unlock(&dup_mutex);
|
||||
|
||||
/*
|
||||
* If we have the checksum and it matches then
|
||||
* read in the fragment block.
|
||||
*
|
||||
* If we *don't* have the checksum, then we are
|
||||
* appending, and the fragment block is on the
|
||||
* "old" filesystem. Read it in and checksum
|
||||
* the entire fragment buffer
|
||||
*/
|
||||
if(!flag) {
|
||||
buffer = get_fragment_cksum(dupl_ptr,
|
||||
data_buffer, fd, &checksum);
|
||||
if(checksum != file_buffer->checksum) {
|
||||
cache_block_put(buffer);
|
||||
continue;
|
||||
}
|
||||
} else if(checksum == file_buffer->checksum)
|
||||
buffer = get_fragment(dupl_ptr->fragment,
|
||||
data_buffer, fd);
|
||||
else
|
||||
continue;
|
||||
|
||||
res = memcmp(file_buffer->data, buffer->data +
|
||||
dupl_ptr->fragment->offset, file_size);
|
||||
cache_block_put(buffer);
|
||||
if(res == 0) {
|
||||
struct file_buffer *dup = malloc(sizeof(*dup));
|
||||
if(dup == NULL)
|
||||
MEM_ERROR();
|
||||
memcpy(dup, file_buffer, sizeof(*dup));
|
||||
cache_block_put(file_buffer);
|
||||
dup->dupl_start = dupl_ptr;
|
||||
dup->duplicate = TRUE;
|
||||
file_buffer = dup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
seq_queue_put(to_main, file_buffer);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef PROCESS_FRAGMENTS_H
|
||||
#define PROCESS_FRAGMENTS_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* process_fragments.h
|
||||
*/
|
||||
|
||||
#define DUP_HASH(a) (a & 0xffff)
|
||||
|
||||
extern void *frag_thrd(void *);
|
||||
#endif
|
259
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.c
Normal file
259
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* progressbar.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/* flag whether progressbar display is enabled or not */
|
||||
int display_progress_bar = FALSE;
|
||||
|
||||
/* flag whether the progress bar is temporarily disbled */
|
||||
int temp_disabled = FALSE;
|
||||
|
||||
int rotate = 0;
|
||||
int cur_uncompressed = 0, estimated_uncompressed = 0;
|
||||
int columns;
|
||||
|
||||
pthread_t progress_thread;
|
||||
pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
static void sigwinch_handler()
|
||||
{
|
||||
struct winsize winsize;
|
||||
|
||||
if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
|
||||
if(isatty(STDOUT_FILENO))
|
||||
ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
|
||||
"columns\n");
|
||||
columns = 80;
|
||||
} else
|
||||
columns = winsize.ws_col;
|
||||
}
|
||||
|
||||
|
||||
static void sigalrm_handler()
|
||||
{
|
||||
rotate = (rotate + 1) % 4;
|
||||
}
|
||||
|
||||
|
||||
void inc_progress_bar()
|
||||
{
|
||||
cur_uncompressed ++;
|
||||
}
|
||||
|
||||
|
||||
void dec_progress_bar(int count)
|
||||
{
|
||||
cur_uncompressed -= count;
|
||||
}
|
||||
|
||||
|
||||
void progress_bar_size(int count)
|
||||
{
|
||||
estimated_uncompressed += count;
|
||||
}
|
||||
|
||||
|
||||
static void progress_bar(long long current, long long max, int columns)
|
||||
{
|
||||
char rotate_list[] = { '|', '/', '-', '\\' };
|
||||
int max_digits, used, hashes, spaces;
|
||||
static int tty = -1;
|
||||
|
||||
if(max == 0)
|
||||
return;
|
||||
|
||||
max_digits = floor(log10(max)) + 1;
|
||||
used = max_digits * 2 + 11;
|
||||
hashes = (current * (columns - used)) / max;
|
||||
spaces = columns - used - hashes;
|
||||
|
||||
if((current > max) || (columns - used < 0))
|
||||
return;
|
||||
|
||||
if(tty == -1)
|
||||
tty = isatty(STDOUT_FILENO);
|
||||
if(!tty) {
|
||||
static long long previous = -1;
|
||||
|
||||
/* Updating much more frequently than this results in huge
|
||||
* log files. */
|
||||
if((current % 100) != 0 && current != max)
|
||||
return;
|
||||
/* Don't update just to rotate the spinner. */
|
||||
if(current == previous)
|
||||
return;
|
||||
previous = current;
|
||||
}
|
||||
|
||||
printf("\r[");
|
||||
|
||||
while (hashes --)
|
||||
putchar('=');
|
||||
|
||||
putchar(rotate_list[rotate]);
|
||||
|
||||
while(spaces --)
|
||||
putchar(' ');
|
||||
|
||||
printf("] %*lld/%*lld", max_digits, current, max_digits, max);
|
||||
printf(" %3lld%%", current * 100 / max);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
void enable_progress_bar()
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar)
|
||||
progress_bar(cur_uncompressed, estimated_uncompressed, columns);
|
||||
temp_disabled = FALSE;
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void disable_progress_bar()
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar)
|
||||
printf("\n");
|
||||
temp_disabled = TRUE;
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void set_progressbar_state(int state)
|
||||
{
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar != state) {
|
||||
if(display_progress_bar && !temp_disabled) {
|
||||
progress_bar(cur_uncompressed, estimated_uncompressed,
|
||||
columns);
|
||||
printf("\n");
|
||||
}
|
||||
display_progress_bar = state;
|
||||
}
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void *progress_thrd(void *arg)
|
||||
{
|
||||
struct timespec requested_time, remaining;
|
||||
struct itimerval itimerval;
|
||||
struct winsize winsize;
|
||||
|
||||
if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
|
||||
if(isatty(STDOUT_FILENO))
|
||||
ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
|
||||
"columns\n");
|
||||
columns = 80;
|
||||
} else
|
||||
columns = winsize.ws_col;
|
||||
signal(SIGWINCH, sigwinch_handler);
|
||||
signal(SIGALRM, sigalrm_handler);
|
||||
|
||||
itimerval.it_value.tv_sec = 0;
|
||||
itimerval.it_value.tv_usec = 250000;
|
||||
itimerval.it_interval.tv_sec = 0;
|
||||
itimerval.it_interval.tv_usec = 250000;
|
||||
setitimer(ITIMER_REAL, &itimerval, NULL);
|
||||
|
||||
requested_time.tv_sec = 0;
|
||||
requested_time.tv_nsec = 250000000;
|
||||
|
||||
while(1) {
|
||||
int res = nanosleep(&requested_time, &remaining);
|
||||
|
||||
if(res == -1 && errno != EINTR)
|
||||
BAD_ERROR("nanosleep failed in progress thread\n");
|
||||
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
if(display_progress_bar && !temp_disabled)
|
||||
progress_bar(cur_uncompressed, estimated_uncompressed,
|
||||
columns);
|
||||
pthread_mutex_unlock(&progress_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_progress_bar()
|
||||
{
|
||||
pthread_create(&progress_thread, NULL, progress_thrd, NULL);
|
||||
}
|
||||
|
||||
|
||||
void progressbar_error(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
|
||||
if(display_progress_bar && !temp_disabled)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
||||
|
||||
void progressbar_info(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
pthread_cleanup_push((void *) pthread_mutex_unlock, &progress_mutex);
|
||||
pthread_mutex_lock(&progress_mutex);
|
||||
|
||||
if(display_progress_bar && !temp_disabled)
|
||||
printf("\n");
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
}
|
||||
|
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.h
Normal file
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/progressbar.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef PROGRESSBAR_H
|
||||
#define PROGRESSBAR_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012, 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* progressbar.h
|
||||
*/
|
||||
|
||||
extern void inc_progress_bar();
|
||||
extern void dec_progress_bar(int count);
|
||||
extern void progress_bar_size(int count);
|
||||
extern void enable_progress_bar();
|
||||
extern void disable_progress_bar();
|
||||
extern void init_progress_bar();
|
||||
extern void set_progressbar_state(int);
|
||||
#endif
|
559
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.c
Normal file
559
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.c
Normal file
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2012, 2014, 2017, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* pseudo.c
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "pseudo.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
extern int read_file(char *filename, char *type, int (parse_line)(char *));
|
||||
|
||||
struct pseudo_dev **pseudo_file = NULL;
|
||||
struct pseudo *pseudo = NULL;
|
||||
int pseudo_count = 0;
|
||||
|
||||
static char *get_component(char *target, char **targname)
|
||||
{
|
||||
char *start;
|
||||
|
||||
start = target;
|
||||
while(*target != '/' && *target != '\0')
|
||||
target ++;
|
||||
|
||||
*targname = strndup(start, target - start);
|
||||
|
||||
while(*target == '/')
|
||||
target ++;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add pseudo device target to the set of pseudo devices. Pseudo_dev
|
||||
* describes the pseudo device attributes.
|
||||
*/
|
||||
struct pseudo *add_pseudo(struct pseudo *pseudo, struct pseudo_dev *pseudo_dev,
|
||||
char *target, char *alltarget)
|
||||
{
|
||||
char *targname;
|
||||
int i;
|
||||
|
||||
target = get_component(target, &targname);
|
||||
|
||||
if(pseudo == NULL) {
|
||||
pseudo = malloc(sizeof(struct pseudo));
|
||||
if(pseudo == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
pseudo->names = 0;
|
||||
pseudo->count = 0;
|
||||
pseudo->name = NULL;
|
||||
}
|
||||
|
||||
for(i = 0; i < pseudo->names; i++)
|
||||
if(strcmp(pseudo->name[i].name, targname) == 0)
|
||||
break;
|
||||
|
||||
if(i == pseudo->names) {
|
||||
/* allocate new name entry */
|
||||
pseudo->names ++;
|
||||
pseudo->name = realloc(pseudo->name, (i + 1) *
|
||||
sizeof(struct pseudo_entry));
|
||||
if(pseudo->name == NULL)
|
||||
MEM_ERROR();
|
||||
pseudo->name[i].name = targname;
|
||||
|
||||
if(target[0] == '\0') {
|
||||
/* at leaf pathname component */
|
||||
pseudo->name[i].pseudo = NULL;
|
||||
pseudo->name[i].pathname = strdup(alltarget);
|
||||
pseudo->name[i].dev = pseudo_dev;
|
||||
} else {
|
||||
/* recurse adding child components */
|
||||
pseudo->name[i].dev = NULL;
|
||||
pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev,
|
||||
target, alltarget);
|
||||
}
|
||||
} else {
|
||||
/* existing matching entry */
|
||||
free(targname);
|
||||
|
||||
if(pseudo->name[i].pseudo == NULL) {
|
||||
/* No sub-directory which means this is the leaf
|
||||
* component of a pre-existing pseudo file.
|
||||
*/
|
||||
if(target[0] != '\0') {
|
||||
/*
|
||||
* entry must exist as either a 'd' type or
|
||||
* 'm' type pseudo file
|
||||
*/
|
||||
if(pseudo->name[i].dev->type == 'd' ||
|
||||
pseudo->name[i].dev->type == 'm')
|
||||
/* recurse adding child components */
|
||||
pseudo->name[i].pseudo =
|
||||
add_pseudo(NULL, pseudo_dev,
|
||||
target, alltarget);
|
||||
else {
|
||||
ERROR_START("%s already exists as a "
|
||||
"non directory.",
|
||||
pseudo->name[i].name);
|
||||
ERROR_EXIT(". Ignoring %s!\n",
|
||||
alltarget);
|
||||
}
|
||||
} else if(memcmp(pseudo_dev, pseudo->name[i].dev,
|
||||
sizeof(struct pseudo_dev)) != 0) {
|
||||
ERROR_START("%s already exists as a different "
|
||||
"pseudo definition.", alltarget);
|
||||
ERROR_EXIT(" Ignoring!\n");
|
||||
} else {
|
||||
ERROR_START("%s already exists as an identical "
|
||||
"pseudo definition!", alltarget);
|
||||
ERROR_EXIT(" Ignoring!\n");
|
||||
}
|
||||
} else {
|
||||
if(target[0] == '\0') {
|
||||
/*
|
||||
* sub-directory exists, which means we can only
|
||||
* add a pseudo file of type 'd' or type 'm'
|
||||
*/
|
||||
if(pseudo->name[i].dev == NULL &&
|
||||
(pseudo_dev->type == 'd' ||
|
||||
pseudo_dev->type == 'm')) {
|
||||
pseudo->name[i].pathname =
|
||||
strdup(alltarget);
|
||||
pseudo->name[i].dev = pseudo_dev;
|
||||
} else {
|
||||
ERROR_START("%s already exists as a "
|
||||
"different pseudo definition.",
|
||||
pseudo->name[i].name);
|
||||
ERROR_EXIT(" Ignoring %s!\n",
|
||||
alltarget);
|
||||
}
|
||||
} else
|
||||
/* recurse adding child components */
|
||||
add_pseudo(pseudo->name[i].pseudo, pseudo_dev,
|
||||
target, alltarget);
|
||||
}
|
||||
}
|
||||
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find subdirectory in pseudo directory referenced by pseudo, matching
|
||||
* filename. If filename doesn't exist or if filename is a leaf file
|
||||
* return NULL
|
||||
*/
|
||||
struct pseudo *pseudo_subdir(char *filename, struct pseudo *pseudo)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(pseudo == NULL)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; i < pseudo->names; i++)
|
||||
if(strcmp(filename, pseudo->name[i].name) == 0)
|
||||
return pseudo->name[i].pseudo;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct pseudo_entry *pseudo_readdir(struct pseudo *pseudo)
|
||||
{
|
||||
if(pseudo == NULL)
|
||||
return NULL;
|
||||
|
||||
while(pseudo->count < pseudo->names) {
|
||||
if(pseudo->name[pseudo->count].dev != NULL)
|
||||
return &pseudo->name[pseudo->count++];
|
||||
else
|
||||
pseudo->count++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int pseudo_exec_file(struct pseudo_dev *dev, int *child)
|
||||
{
|
||||
int res, pipefd[2];
|
||||
|
||||
res = pipe(pipefd);
|
||||
if(res == -1) {
|
||||
ERROR("Executing dynamic pseudo file, pipe failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*child = fork();
|
||||
if(*child == -1) {
|
||||
ERROR("Executing dynamic pseudo file, fork failed\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(*child == 0) {
|
||||
close(pipefd[0]);
|
||||
close(STDOUT_FILENO);
|
||||
res = dup(pipefd[1]);
|
||||
if(res == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
execl("/bin/sh", "sh", "-c", dev->command, (char *) NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
close(pipefd[1]);
|
||||
return pipefd[0];
|
||||
|
||||
failed:
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void add_pseudo_file(struct pseudo_dev *dev)
|
||||
{
|
||||
pseudo_file = realloc(pseudo_file, (pseudo_count + 1) *
|
||||
sizeof(struct pseudo_dev *));
|
||||
if(pseudo_file == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
dev->pseudo_id = pseudo_count;
|
||||
pseudo_file[pseudo_count ++] = dev;
|
||||
}
|
||||
|
||||
|
||||
struct pseudo_dev *get_pseudo_file(int pseudo_id)
|
||||
{
|
||||
return pseudo_file[pseudo_id];
|
||||
}
|
||||
|
||||
|
||||
int read_pseudo_def(char *def)
|
||||
{
|
||||
int n, bytes;
|
||||
int quoted = 0;
|
||||
unsigned int major = 0, minor = 0, mode;
|
||||
char type, *ptr;
|
||||
char suid[100], sgid[100]; /* overflow safe */
|
||||
char *filename, *name;
|
||||
char *orig_def = def;
|
||||
long long uid, gid;
|
||||
struct pseudo_dev *dev;
|
||||
|
||||
/*
|
||||
* Scan for filename, don't use sscanf() and "%s" because
|
||||
* that can't handle filenames with spaces.
|
||||
*
|
||||
* Filenames with spaces should either escape (backslash) the
|
||||
* space or use double quotes.
|
||||
*/
|
||||
filename = malloc(strlen(def) + 1);
|
||||
if(filename == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
for(name = filename; (quoted || !isspace(*def)) && *def != '\0';) {
|
||||
if(*def == '"') {
|
||||
quoted = !quoted;
|
||||
def ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(*def == '\\') {
|
||||
def ++;
|
||||
if (*def == '\0')
|
||||
break;
|
||||
}
|
||||
*name ++ = *def ++;
|
||||
}
|
||||
*name = '\0';
|
||||
|
||||
/* Skip any leading slashes (/) */
|
||||
for(name = filename; *name == '/'; name ++);
|
||||
|
||||
if(*name == '\0') {
|
||||
ERROR("Not enough or invalid arguments in pseudo file "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
goto error;
|
||||
}
|
||||
|
||||
n = sscanf(def, " %c %o %99s %99s %n", &type, &mode, suid, sgid,
|
||||
&bytes);
|
||||
def += bytes;
|
||||
|
||||
if(n < 4) {
|
||||
ERROR("Not enough or invalid arguments in pseudo file "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
switch(n) {
|
||||
case -1:
|
||||
/* FALLTHROUGH */
|
||||
case 0:
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
ERROR("Couldn't parse filename, type or octal mode\n");
|
||||
ERROR("If the filename has spaces, either quote it, or "
|
||||
"backslash the spaces\n");
|
||||
break;
|
||||
case 2:
|
||||
ERROR("Read filename, type and mode, but failed to "
|
||||
"read or match uid\n");
|
||||
break;
|
||||
default:
|
||||
ERROR("Read filename, type, mode and uid, but failed "
|
||||
"to read or match gid\n");
|
||||
break;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case 'b':
|
||||
/* FALLTHROUGH */
|
||||
case 'c':
|
||||
n = sscanf(def, "%u %u %n", &major, &minor, &bytes);
|
||||
def += bytes;
|
||||
|
||||
if(n < 2) {
|
||||
ERROR("Not enough or invalid arguments in %s device "
|
||||
"pseudo file definition \"%s\"\n", type == 'b' ?
|
||||
"block" : "character", orig_def);
|
||||
if(n < 1)
|
||||
ERROR("Read filename, type, mode, uid and gid, "
|
||||
"but failed to read or match major\n");
|
||||
else
|
||||
ERROR("Read filename, type, mode, uid, gid "
|
||||
"and major, but failed to read or "
|
||||
"match minor\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(major > 0xfff) {
|
||||
ERROR("Major %d out of range\n", major);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(minor > 0xfffff) {
|
||||
ERROR("Minor %d out of range\n", minor);
|
||||
goto error;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 'd':
|
||||
/* FALLTHROUGH */
|
||||
case 'm':
|
||||
/*
|
||||
* Check for trailing junk after expected arguments
|
||||
*/
|
||||
if(def[0] != '\0') {
|
||||
ERROR("Unexpected tailing characters in pseudo file "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if(def[0] == '\0') {
|
||||
ERROR("Not enough arguments in dynamic file pseudo "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
ERROR("Expected command, which can be an executable "
|
||||
"or a piece of shell script\n");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if(def[0] == '\0') {
|
||||
ERROR("Not enough arguments in symlink pseudo "
|
||||
"definition \"%s\"\n", orig_def);
|
||||
ERROR("Expected symlink\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(strlen(def) > 65535) {
|
||||
ERROR("Symlink pseudo definition %s is greater than 65535"
|
||||
" bytes!\n", def);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Unsupported type %c\n", type);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
if(mode > 07777) {
|
||||
ERROR("Mode %o out of range\n", mode);
|
||||
goto error;
|
||||
}
|
||||
|
||||
uid = strtoll(suid, &ptr, 10);
|
||||
if(*ptr == '\0') {
|
||||
if(uid < 0 || uid > ((1LL << 32) - 1)) {
|
||||
ERROR("Uid %s out of range\n", suid);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
struct passwd *pwuid = getpwnam(suid);
|
||||
if(pwuid)
|
||||
uid = pwuid->pw_uid;
|
||||
else {
|
||||
ERROR("Uid %s invalid uid or unknown user\n", suid);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
gid = strtoll(sgid, &ptr, 10);
|
||||
if(*ptr == '\0') {
|
||||
if(gid < 0 || gid > ((1LL << 32) - 1)) {
|
||||
ERROR("Gid %s out of range\n", sgid);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
struct group *grgid = getgrnam(sgid);
|
||||
if(grgid)
|
||||
gid = grgid->gr_gid;
|
||||
else {
|
||||
ERROR("Gid %s invalid uid or unknown user\n", sgid);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case 'b':
|
||||
mode |= S_IFBLK;
|
||||
break;
|
||||
case 'c':
|
||||
mode |= S_IFCHR;
|
||||
break;
|
||||
case 'd':
|
||||
mode |= S_IFDIR;
|
||||
break;
|
||||
case 'f':
|
||||
mode |= S_IFREG;
|
||||
break;
|
||||
case 's':
|
||||
/* permissions on symlinks are always rwxrwxrwx */
|
||||
mode = 0777 | S_IFLNK;
|
||||
break;
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(struct pseudo_dev));
|
||||
if(dev == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
dev->type = type;
|
||||
dev->mode = mode;
|
||||
dev->uid = uid;
|
||||
dev->gid = gid;
|
||||
dev->major = major;
|
||||
dev->minor = minor;
|
||||
if(type == 'f') {
|
||||
dev->command = strdup(def);
|
||||
add_pseudo_file(dev);
|
||||
}
|
||||
if(type == 's')
|
||||
dev->symlink = strdup(def);
|
||||
|
||||
pseudo = add_pseudo(pseudo, dev, name, name);
|
||||
|
||||
free(filename);
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
ERROR("Pseudo definitions should be of the format\n");
|
||||
ERROR("\tfilename d mode uid gid\n");
|
||||
ERROR("\tfilename m mode uid gid\n");
|
||||
ERROR("\tfilename b mode uid gid major minor\n");
|
||||
ERROR("\tfilename c mode uid gid major minor\n");
|
||||
ERROR("\tfilename f mode uid gid command\n");
|
||||
ERROR("\tfilename s mode uid gid symlink\n");
|
||||
free(filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int read_pseudo_file(char *filename)
|
||||
{
|
||||
return read_file(filename, "pseudo", read_pseudo_def);
|
||||
}
|
||||
|
||||
|
||||
struct pseudo *get_pseudo()
|
||||
{
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SQUASHFS_TRACE
|
||||
static void dump_pseudo(struct pseudo *pseudo, char *string)
|
||||
{
|
||||
int i, res;
|
||||
char *path;
|
||||
|
||||
for(i = 0; i < pseudo->names; i++) {
|
||||
struct pseudo_entry *entry = &pseudo->name[i];
|
||||
if(string) {
|
||||
res = asprintf(&path, "%s/%s", string, entry->name);
|
||||
if(res == -1)
|
||||
BAD_ERROR("asprintf failed in dump_pseudo\n");
|
||||
} else
|
||||
path = entry->name;
|
||||
if(entry->dev)
|
||||
ERROR("%s %c 0%o %d %d %d %d\n", path, entry->dev->type,
|
||||
entry->dev->mode & ~S_IFMT, entry->dev->uid,
|
||||
entry->dev->gid, entry->dev->major,
|
||||
entry->dev->minor);
|
||||
if(entry->pseudo)
|
||||
dump_pseudo(entry->pseudo, path);
|
||||
if(string)
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_pseudos()
|
||||
{
|
||||
if (pseudo)
|
||||
dump_pseudo(pseudo, NULL);
|
||||
}
|
||||
#else
|
||||
void dump_pseudos()
|
||||
{
|
||||
}
|
||||
#endif
|
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.h
Normal file
61
SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef PSEUDO_H
|
||||
#define PSEUDO_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* pseudo.h
|
||||
*/
|
||||
struct pseudo_dev {
|
||||
char type;
|
||||
unsigned int mode;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int major;
|
||||
unsigned int minor;
|
||||
int pseudo_id;
|
||||
union {
|
||||
char *command;
|
||||
char *symlink;
|
||||
};
|
||||
};
|
||||
|
||||
struct pseudo_entry {
|
||||
char *name;
|
||||
char *pathname;
|
||||
struct pseudo *pseudo;
|
||||
struct pseudo_dev *dev;
|
||||
};
|
||||
|
||||
struct pseudo {
|
||||
int names;
|
||||
int count;
|
||||
struct pseudo_entry *name;
|
||||
};
|
||||
|
||||
extern int read_pseudo_def(char *);
|
||||
extern int read_pseudo_file(char *);
|
||||
extern struct pseudo *pseudo_subdir(char *, struct pseudo *);
|
||||
extern struct pseudo_entry *pseudo_readdir(struct pseudo *);
|
||||
extern struct pseudo_dev *get_pseudo_file(int);
|
||||
extern int pseudo_exec_file(struct pseudo_dev *, int *);
|
||||
extern struct pseudo *get_pseudo();
|
||||
extern void dump_pseudos();
|
||||
#endif
|
150
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_file.c
Normal file
150
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_file.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2012
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_file.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define MAX_LINE 16384
|
||||
|
||||
/*
|
||||
* Read file, passing each line to parse_line() for
|
||||
* parsing.
|
||||
*
|
||||
* Lines can be split across multiple lines using "\".
|
||||
*
|
||||
* Blank lines and comment lines indicated by # are supported.
|
||||
*/
|
||||
int read_file(char *filename, char *type, int (parse_line)(char *))
|
||||
{
|
||||
FILE *fd;
|
||||
char *def, *err, *line = NULL;
|
||||
int res, size = 0;
|
||||
|
||||
fd = fopen(filename, "r");
|
||||
if(fd == NULL) {
|
||||
ERROR("Could not open %s device file \"%s\" because %s\n",
|
||||
type, filename, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
int total = 0;
|
||||
|
||||
while(1) {
|
||||
int len;
|
||||
|
||||
if(total + (MAX_LINE + 1) > size) {
|
||||
line = realloc(line, size += (MAX_LINE + 1));
|
||||
if(line == NULL)
|
||||
MEM_ERROR();
|
||||
}
|
||||
|
||||
err = fgets(line + total, MAX_LINE + 1, fd);
|
||||
if(err == NULL)
|
||||
break;
|
||||
|
||||
len = strlen(line + total);
|
||||
total += len;
|
||||
|
||||
if(len == MAX_LINE && line[total - 1] != '\n') {
|
||||
/* line too large */
|
||||
ERROR("Line too long when reading "
|
||||
"%s file \"%s\", larger than "
|
||||
"%d bytes\n", type, filename, MAX_LINE);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove '\n' terminator if it exists (the last line
|
||||
* in the file may not be '\n' terminated)
|
||||
*/
|
||||
if(len && line[total - 1] == '\n') {
|
||||
line[-- total] = '\0';
|
||||
len --;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no line continuation then jump out to
|
||||
* process line. Note, we have to be careful to
|
||||
* check for "\\" (backslashed backslash) and to
|
||||
* ensure we don't look at the previous line
|
||||
*/
|
||||
if(len == 0 || line[total - 1] != '\\' || (len >= 2 &&
|
||||
strcmp(line + total - 2, "\\\\") == 0))
|
||||
break;
|
||||
else
|
||||
total --;
|
||||
}
|
||||
|
||||
if(err == NULL) {
|
||||
if(ferror(fd)) {
|
||||
ERROR("Reading %s file \"%s\" failed "
|
||||
"because %s\n", type, filename,
|
||||
strerror(errno));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* At EOF, normally we'll be finished, but, have to
|
||||
* check for special case where we had "\" line
|
||||
* continuation and then hit EOF immediately afterwards
|
||||
*/
|
||||
if(total == 0)
|
||||
break;
|
||||
else
|
||||
line[total] = '\0';
|
||||
}
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
for(def = line; isspace(*def); def ++);
|
||||
|
||||
/* if line is now empty after skipping characters, skip it */
|
||||
if(*def == '\0')
|
||||
continue;
|
||||
|
||||
/* if comment line, skip */
|
||||
if(*def == '#')
|
||||
continue;
|
||||
|
||||
res = parse_line(def);
|
||||
if(res == FALSE)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
free(line);
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
fclose(fd);
|
||||
free(line);
|
||||
return FALSE;
|
||||
}
|
996
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.c
Normal file
996
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.c
Normal file
|
@ -0,0 +1,996 @@
|
|||
/*
|
||||
* Read a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
* 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_fs.c
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_swap.h"
|
||||
#include "compressor.h"
|
||||
#include "xattr.h"
|
||||
#include "error.h"
|
||||
#include "mksquashfs.h"
|
||||
|
||||
int read_block(int fd, long long start, long long *next, int expected,
|
||||
void *block)
|
||||
{
|
||||
unsigned short c_byte;
|
||||
int res, compressed;
|
||||
int outlen = expected ? expected : SQUASHFS_METADATA_SIZE;
|
||||
|
||||
/* Read block size */
|
||||
res = read_fs_bytes(fd, start, 2, &c_byte);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
|
||||
SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
|
||||
compressed = SQUASHFS_COMPRESSED(c_byte);
|
||||
c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
|
||||
|
||||
/*
|
||||
* The block size should not be larger than
|
||||
* the uncompressed size (or max uncompressed size if
|
||||
* expected is 0)
|
||||
*/
|
||||
if (c_byte > outlen)
|
||||
return 0;
|
||||
|
||||
if(compressed) {
|
||||
char buffer[c_byte];
|
||||
int error;
|
||||
|
||||
res = read_fs_bytes(fd, start + 2, c_byte, buffer);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
|
||||
res = compressor_uncompress(comp, block, buffer, c_byte,
|
||||
outlen, &error);
|
||||
if(res == -1) {
|
||||
ERROR("%s uncompress failed with error code %d\n",
|
||||
comp->name, error);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
res = read_fs_bytes(fd, start + 2, c_byte, block);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
res = c_byte;
|
||||
}
|
||||
|
||||
if(next)
|
||||
*next = start + 2 + c_byte;
|
||||
|
||||
/*
|
||||
* if expected, then check the (uncompressed) return data
|
||||
* is of the expected size
|
||||
*/
|
||||
if(expected && expected != res)
|
||||
return 0;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#define NO_BYTES(SIZE) \
|
||||
(bytes - (cur_ptr - inode_table) < (SIZE))
|
||||
|
||||
#define NO_INODE_BYTES(INODE) NO_BYTES(sizeof(struct INODE))
|
||||
|
||||
unsigned char *scan_inode_table(int fd, long long start, long long end,
|
||||
long long root_inode_start, int root_inode_offset,
|
||||
struct squashfs_super_block *sBlk, union squashfs_inode_header
|
||||
*dir_inode, unsigned int *root_inode_block, unsigned int
|
||||
*root_inode_size, long long *uncompressed_file, unsigned int
|
||||
*uncompressed_directory, int *file_count, int *sym_count, int
|
||||
*dev_count, int *dir_count, int *fifo_count, int *sock_count,
|
||||
unsigned int *id_table)
|
||||
{
|
||||
unsigned char *cur_ptr;
|
||||
unsigned char *inode_table = NULL;
|
||||
int byte, files = 0;
|
||||
unsigned int directory_start_block, bytes = 0, size = 0;
|
||||
struct squashfs_base_inode_header base;
|
||||
|
||||
TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start "
|
||||
"0x%llx\n", start, end, root_inode_start);
|
||||
|
||||
*root_inode_block = UINT_MAX;
|
||||
while(start < end) {
|
||||
if(start == root_inode_start) {
|
||||
TRACE("scan_inode_table: read compressed block 0x%llx "
|
||||
"containing root inode\n", start);
|
||||
*root_inode_block = bytes;
|
||||
}
|
||||
if(size - bytes < SQUASHFS_METADATA_SIZE) {
|
||||
inode_table = realloc(inode_table, size
|
||||
+= SQUASHFS_METADATA_SIZE);
|
||||
if(inode_table == NULL)
|
||||
MEM_ERROR();
|
||||
}
|
||||
TRACE("scan_inode_table: reading block 0x%llx\n", start);
|
||||
byte = read_block(fd, start, &start, 0, inode_table + bytes);
|
||||
if(byte == 0)
|
||||
goto corrupted;
|
||||
|
||||
bytes += byte;
|
||||
|
||||
/* If this is not the last metadata block in the inode table
|
||||
* then it should be SQUASHFS_METADATA_SIZE in size.
|
||||
* Note, we can't use expected in read_block() above for this
|
||||
* because we don't know if this is the last block until
|
||||
* after reading.
|
||||
*/
|
||||
if(start != end && byte != SQUASHFS_METADATA_SIZE)
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/*
|
||||
* We expect to have found the metadata block containing the
|
||||
* root inode in the above inode_table metadata block scan. If it
|
||||
* hasn't been found then the filesystem is corrupted
|
||||
*/
|
||||
if(*root_inode_block == UINT_MAX)
|
||||
goto corrupted;
|
||||
|
||||
/*
|
||||
* The number of bytes available after the root inode medata block
|
||||
* should be at least the root inode offset + the size of a
|
||||
* regular directory inode, if not the filesystem is corrupted
|
||||
*
|
||||
* +-----------------------+-----------------------+
|
||||
* | | directory |
|
||||
* | | inode |
|
||||
* +-----------------------+-----------------------+
|
||||
* ^ ^ ^
|
||||
* *root_inode_block root_inode_offset bytes
|
||||
*/
|
||||
if((bytes - *root_inode_block) < (root_inode_offset +
|
||||
sizeof(struct squashfs_dir_inode_header)))
|
||||
goto corrupted;
|
||||
|
||||
/*
|
||||
* Read last inode entry which is the root directory inode, and obtain
|
||||
* the last directory start block index. This is used when calculating
|
||||
* the total uncompressed directory size. The directory bytes in the
|
||||
* last * block will be counted as normal.
|
||||
*
|
||||
* Note, the previous check ensures the following calculation won't
|
||||
* underflow, and we won't access beyond the buffer
|
||||
*/
|
||||
*root_inode_size = bytes - (*root_inode_block + root_inode_offset);
|
||||
bytes = *root_inode_block + root_inode_offset;
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER(inode_table + bytes, &dir_inode->dir);
|
||||
|
||||
if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE)
|
||||
directory_start_block = dir_inode->dir.start_block;
|
||||
else if(dir_inode->base.inode_type == SQUASHFS_LDIR_TYPE) {
|
||||
if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER(inode_table + bytes,
|
||||
&dir_inode->ldir);
|
||||
directory_start_block = dir_inode->ldir.start_block;
|
||||
} else
|
||||
/* bad type, corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
get_uid(id_table[dir_inode->base.uid]);
|
||||
get_guid(id_table[dir_inode->base.guid]);
|
||||
|
||||
/* allocate fragment to file mapping table */
|
||||
file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
|
||||
if(file_mapping == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
for(cur_ptr = inode_table; cur_ptr < inode_table + bytes; files ++) {
|
||||
if(NO_INODE_BYTES(squashfs_base_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
|
||||
|
||||
TRACE("scan_inode_table: processing inode @ byte position "
|
||||
"0x%x, type 0x%x\n",
|
||||
(unsigned int) (cur_ptr - inode_table),
|
||||
base.inode_type);
|
||||
|
||||
get_uid(id_table[base.uid]);
|
||||
get_guid(id_table[base.guid]);
|
||||
|
||||
switch(base.inode_type) {
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
struct squashfs_reg_inode_header inode;
|
||||
int frag_bytes, blocks, i;
|
||||
long long start, file_bytes = 0;
|
||||
unsigned int *block_list;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_reg_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
|
||||
|
||||
frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
0 : inode.file_size % sBlk->block_size;
|
||||
blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(inode.file_size + sBlk->block_size - 1) >>
|
||||
sBlk->block_log : inode.file_size >>
|
||||
sBlk->block_log;
|
||||
start = inode.start_block;
|
||||
|
||||
TRACE("scan_inode_table: regular file, file_size %d, "
|
||||
"blocks %d\n", inode.file_size, blocks);
|
||||
|
||||
if(NO_BYTES(blocks * sizeof(unsigned int)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
block_list = malloc(blocks * sizeof(unsigned int));
|
||||
if(block_list == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
cur_ptr += sizeof(inode);
|
||||
SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
|
||||
|
||||
*uncompressed_file += inode.file_size;
|
||||
(*file_count) ++;
|
||||
|
||||
for(i = 0; i < blocks; i++)
|
||||
file_bytes +=
|
||||
SQUASHFS_COMPRESSED_SIZE_BLOCK
|
||||
(block_list[i]);
|
||||
|
||||
if(inode.fragment != SQUASHFS_INVALID_FRAG &&
|
||||
inode.fragment >= sBlk->fragments) {
|
||||
free(block_list);
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
add_file(start, inode.file_size, file_bytes,
|
||||
block_list, blocks, inode.fragment,
|
||||
inode.offset, frag_bytes);
|
||||
|
||||
cur_ptr += blocks * sizeof(unsigned int);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LREG_TYPE: {
|
||||
struct squashfs_lreg_inode_header inode;
|
||||
int frag_bytes, blocks, i;
|
||||
long long start, file_bytes = 0;
|
||||
unsigned int *block_list;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_lreg_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
|
||||
|
||||
frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
0 : inode.file_size % sBlk->block_size;
|
||||
blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(inode.file_size + sBlk->block_size - 1) >>
|
||||
sBlk->block_log : inode.file_size >>
|
||||
sBlk->block_log;
|
||||
start = inode.start_block;
|
||||
|
||||
TRACE("scan_inode_table: extended regular "
|
||||
"file, file_size %lld, blocks %d\n",
|
||||
inode.file_size, blocks);
|
||||
|
||||
if(NO_BYTES(blocks * sizeof(unsigned int)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
block_list = malloc(blocks * sizeof(unsigned int));
|
||||
if(block_list == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
cur_ptr += sizeof(inode);
|
||||
SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
|
||||
|
||||
*uncompressed_file += inode.file_size;
|
||||
(*file_count) ++;
|
||||
|
||||
for(i = 0; i < blocks; i++)
|
||||
file_bytes +=
|
||||
SQUASHFS_COMPRESSED_SIZE_BLOCK
|
||||
(block_list[i]);
|
||||
|
||||
if(inode.fragment != SQUASHFS_INVALID_FRAG &&
|
||||
inode.fragment >= sBlk->fragments) {
|
||||
free(block_list);
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
add_file(start, inode.file_size, file_bytes,
|
||||
block_list, blocks, inode.fragment,
|
||||
inode.offset, frag_bytes);
|
||||
|
||||
cur_ptr += blocks * sizeof(unsigned int);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE:
|
||||
case SQUASHFS_LSYMLINK_TYPE: {
|
||||
struct squashfs_symlink_inode_header inode;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_symlink_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
|
||||
|
||||
(*sym_count) ++;
|
||||
|
||||
if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) {
|
||||
if(NO_BYTES(inode.symlink_size +
|
||||
sizeof(unsigned int)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
cur_ptr += sizeof(inode) + inode.symlink_size +
|
||||
sizeof(unsigned int);
|
||||
} else {
|
||||
if(NO_BYTES(inode.symlink_size))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
cur_ptr += sizeof(inode) + inode.symlink_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
struct squashfs_dir_inode_header dir_inode;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_dir_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
|
||||
|
||||
if(dir_inode.start_block < directory_start_block)
|
||||
*uncompressed_directory += dir_inode.file_size;
|
||||
|
||||
(*dir_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_dir_inode_header);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
struct squashfs_ldir_inode_header dir_inode;
|
||||
int i;
|
||||
|
||||
if(NO_INODE_BYTES(squashfs_ldir_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
|
||||
|
||||
if(dir_inode.start_block < directory_start_block)
|
||||
*uncompressed_directory += dir_inode.file_size;
|
||||
|
||||
(*dir_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ldir_inode_header);
|
||||
|
||||
for(i = 0; i < dir_inode.i_count; i++) {
|
||||
struct squashfs_dir_index index;
|
||||
|
||||
if(NO_BYTES(sizeof(index)))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
|
||||
|
||||
if(NO_BYTES(index.size + 1))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
cur_ptr += sizeof(index) + index.size + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_dev_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*dev_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_dev_inode_header);
|
||||
break;
|
||||
case SQUASHFS_LBLKDEV_TYPE:
|
||||
case SQUASHFS_LCHRDEV_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_ldev_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*dev_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ldev_inode_header);
|
||||
break;
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_ipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*fifo_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ipc_inode_header);
|
||||
break;
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_lipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*fifo_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_lipc_inode_header);
|
||||
break;
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_ipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*sock_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_ipc_inode_header);
|
||||
break;
|
||||
case SQUASHFS_LSOCKET_TYPE:
|
||||
if(NO_INODE_BYTES(squashfs_lipc_inode_header))
|
||||
/* corrupted filesystem */
|
||||
goto corrupted;
|
||||
|
||||
(*sock_count) ++;
|
||||
cur_ptr += sizeof(struct squashfs_lipc_inode_header);
|
||||
break;
|
||||
default:
|
||||
ERROR("Unknown inode type %d in scan_inode_table!\n",
|
||||
base.inode_type);
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Read existing filesystem, %d inodes scanned\n", files);
|
||||
return inode_table;
|
||||
|
||||
corrupted:
|
||||
ERROR("scan_inode_table: filesystem corruption detected in "
|
||||
"scanning metadata\n");
|
||||
free(inode_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source)
|
||||
{
|
||||
int res, bytes = 0;
|
||||
char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
|
||||
|
||||
res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
|
||||
sBlk);
|
||||
if(res == 0) {
|
||||
ERROR("Can't find a SQUASHFS superblock on %s\n",
|
||||
source);
|
||||
ERROR("Wrong filesystem or filesystem is corrupted!\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
|
||||
|
||||
if(sBlk->s_magic != SQUASHFS_MAGIC) {
|
||||
if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP)
|
||||
ERROR("Pre 4.0 big-endian filesystem on %s, appending"
|
||||
" to this is unsupported\n", source);
|
||||
else {
|
||||
ERROR("Can't find a SQUASHFS superblock on %s\n",
|
||||
source);
|
||||
ERROR("Wrong filesystem or filesystem is corrupted!\n");
|
||||
}
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Check the MAJOR & MINOR versions */
|
||||
if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
|
||||
if(sBlk->s_major < 4)
|
||||
ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem."
|
||||
" Appending\nto SQUASHFS %d.%d filesystems is "
|
||||
"not supported. Please convert it to a "
|
||||
"SQUASHFS 4 filesystem\n", source,
|
||||
sBlk->s_major,
|
||||
sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
|
||||
else
|
||||
ERROR("Filesystem on %s is %d.%d, which is a later "
|
||||
"filesystem version than I support\n",
|
||||
source, sBlk->s_major, sBlk->s_minor);
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/* Check the compression type */
|
||||
comp = lookup_compressor_id(sBlk->compression);
|
||||
if(!comp->supported) {
|
||||
ERROR("Filesystem on %s uses %s compression, this is "
|
||||
"unsupported by this version\n", source, comp->name);
|
||||
ERROR("Compressors available:\n");
|
||||
display_compressors("", "");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read extended superblock information from disk.
|
||||
*
|
||||
* Read compressor specific options from disk if present, and pass
|
||||
* to compressor to set compressor options.
|
||||
*
|
||||
* Note, if there's no compressor options present, the compressor
|
||||
* is still called to set the default options (the defaults may have
|
||||
* been changed by the user specifying options on the command
|
||||
* line which need to be over-ridden).
|
||||
*
|
||||
* Compressor_extract_options is also used to ensure that
|
||||
* we know how decompress a filesystem compressed with these
|
||||
* compression options.
|
||||
*/
|
||||
if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
|
||||
bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
|
||||
|
||||
if(bytes == 0) {
|
||||
ERROR("Failed to read compressor options from append "
|
||||
"filesystem\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
}
|
||||
|
||||
res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes);
|
||||
if(res == -1) {
|
||||
ERROR("Compressor failed to set compressor options\n");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
printf("Found a valid %sSQUASHFS superblock on %s.\n",
|
||||
SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source);
|
||||
printf("\tCompression used %s\n", comp->name);
|
||||
printf("\tInodes are %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
|
||||
printf("\tData is %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
|
||||
printf("\tFragments are %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
|
||||
printf("\tXattrs are %scompressed\n",
|
||||
SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : "");
|
||||
printf("\tFragments are %spresent in the filesystem\n",
|
||||
SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
|
||||
printf("\tAlways-use-fragments option is %sspecified\n",
|
||||
SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
|
||||
printf("\tDuplicates are %sremoved\n",
|
||||
SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
|
||||
printf("\tXattrs are %sstored\n",
|
||||
SQUASHFS_NO_XATTRS(sBlk->flags) ? "not " : "");
|
||||
printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n",
|
||||
sBlk->bytes_used / 1024.0, sBlk->bytes_used
|
||||
/ (1024.0 * 1024.0));
|
||||
printf("\tBlock size %d\n", sBlk->block_size);
|
||||
printf("\tNumber of fragments %d\n", sBlk->fragments);
|
||||
printf("\tNumber of inodes %d\n", sBlk->inodes);
|
||||
printf("\tNumber of ids %d\n", sBlk->no_ids);
|
||||
TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start);
|
||||
TRACE("sBlk->directory_table_start %llx\n",
|
||||
sBlk->directory_table_start);
|
||||
TRACE("sBlk->id_table_start %llx\n", sBlk->id_table_start);
|
||||
TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start);
|
||||
TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start);
|
||||
TRACE("sBlk->xattr_id_table_start %llx\n", sBlk->xattr_id_table_start);
|
||||
printf("\n");
|
||||
|
||||
return comp;
|
||||
|
||||
failed_mount:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
unsigned char *squashfs_readdir(int fd, int root_entries,
|
||||
unsigned int directory_start_block, int offset, int size,
|
||||
unsigned int *last_directory_block, struct squashfs_super_block *sBlk,
|
||||
void (push_directory_entry)(char *, squashfs_inode, int, int))
|
||||
{
|
||||
struct squashfs_dir_header dirh;
|
||||
char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__ ((aligned));
|
||||
struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
|
||||
unsigned char *directory_table = NULL;
|
||||
int byte, bytes = 0, dir_count;
|
||||
long long start = sBlk->directory_table_start + directory_start_block,
|
||||
last_start_block = start;
|
||||
|
||||
size += offset;
|
||||
directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) &
|
||||
~(SQUASHFS_METADATA_SIZE - 1));
|
||||
if(directory_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
while(bytes < size) {
|
||||
int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ?
|
||||
SQUASHFS_METADATA_SIZE : 0;
|
||||
|
||||
TRACE("squashfs_readdir: reading block 0x%llx, bytes read so "
|
||||
"far %d\n", start, bytes);
|
||||
|
||||
last_start_block = start;
|
||||
byte = read_block(fd, start, &start, expected, directory_table + bytes);
|
||||
if(byte == 0) {
|
||||
ERROR("Failed to read directory\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(directory_table);
|
||||
return NULL;
|
||||
}
|
||||
bytes += byte;
|
||||
}
|
||||
|
||||
if(!root_entries)
|
||||
goto all_done;
|
||||
|
||||
bytes = offset;
|
||||
while(bytes < size) {
|
||||
SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
free(directory_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE("squashfs_readdir: Read directory header @ byte position "
|
||||
"0x%x, 0x%x directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
while(dir_count--) {
|
||||
SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
free(directory_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_readdir: pushing directory entry %s, "
|
||||
"inode %x:%x, type 0x%x\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
push_directory_entry(dire->name,
|
||||
SQUASHFS_MKINODE(dirh.start_block,
|
||||
dire->offset), dirh.inode_number +
|
||||
dire->inode_number, dire->type);
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
all_done:
|
||||
*last_directory_block = (unsigned int) last_start_block -
|
||||
sBlk->directory_table_start;
|
||||
return directory_table;
|
||||
}
|
||||
|
||||
|
||||
unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int indexes = SQUASHFS_ID_BLOCKS(sBlk->no_ids);
|
||||
long long index[indexes];
|
||||
int bytes = SQUASHFS_ID_BYTES(sBlk->no_ids);
|
||||
unsigned int *id_table;
|
||||
int res, i;
|
||||
|
||||
id_table = malloc(bytes);
|
||||
if(id_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->id_table_start,
|
||||
SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read id table index\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(id_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_ID_BLOCKS(index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, index[i], NULL, expected,
|
||||
((unsigned char *) id_table) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read id table block %d, from 0x%llx, length %d\n", i,
|
||||
index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read id table block %d, from 0x%llx, "
|
||||
"length %d\n", i, index[i], length);
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(id_table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids);
|
||||
|
||||
for(i = 0; i < sBlk->no_ids; i++) {
|
||||
TRACE("Adding id %d to id tables\n", id_table[i]);
|
||||
create_id(id_table[i]);
|
||||
}
|
||||
|
||||
return id_table;
|
||||
}
|
||||
|
||||
|
||||
struct squashfs_fragment_entry *read_fragment_table(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int res, i;
|
||||
int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk->fragments);
|
||||
int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
|
||||
long long fragment_table_index[indexes];
|
||||
struct squashfs_fragment_entry *fragment_table;
|
||||
|
||||
TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
|
||||
"from 0x%llx\n", sBlk->fragments, indexes,
|
||||
sBlk->fragment_table_start);
|
||||
|
||||
fragment_table = malloc(bytes);
|
||||
if(fragment_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->fragment_table_start,
|
||||
SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments),
|
||||
fragment_table_index);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read fragment table index\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(fragment_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, fragment_table_index[i], NULL,
|
||||
expected, ((unsigned char *) fragment_table) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
|
||||
i, fragment_table_index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read fragment table block %d, from "
|
||||
"0x%llx, length %d\n", i,
|
||||
fragment_table_index[i], length);
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(fragment_table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < sBlk->fragments; i++)
|
||||
SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
|
||||
|
||||
return fragment_table;
|
||||
}
|
||||
|
||||
|
||||
squashfs_inode *read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes);
|
||||
int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes);
|
||||
long long index[indexes];
|
||||
int res, i;
|
||||
squashfs_inode *inode_lookup_table;
|
||||
|
||||
inode_lookup_table = malloc(lookup_bytes);
|
||||
if(inode_lookup_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->lookup_table_start,
|
||||
SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read inode lookup table index\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(inode_lookup_table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
lookup_bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, index[i], NULL, expected,
|
||||
((unsigned char *) inode_lookup_table) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read inode lookup table block %d, from 0x%llx, length "
|
||||
"%d\n", i, index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read inode lookup table block %d, "
|
||||
"from 0x%llx, length %d\n", i, index[i],
|
||||
length);
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
free(inode_lookup_table);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_LONG_LONGS(inode_lookup_table, sBlk->inodes);
|
||||
|
||||
return inode_lookup_table;
|
||||
}
|
||||
|
||||
|
||||
long long read_filesystem(char *root_name, int fd, struct squashfs_super_block *sBlk,
|
||||
char **cinode_table, char **data_cache, char **cdirectory_table,
|
||||
char **directory_data_cache, unsigned int *last_directory_block,
|
||||
unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
|
||||
unsigned int *root_inode_size, unsigned int *inode_dir_start_block,
|
||||
int *file_count, int *sym_count, int *dev_count, int *dir_count,
|
||||
int *fifo_count, int *sock_count, long long *uncompressed_file,
|
||||
unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
|
||||
unsigned int *inode_dir_inode_number,
|
||||
unsigned int *inode_dir_parent_inode,
|
||||
void (push_directory_entry)(char *, squashfs_inode, int, int),
|
||||
struct squashfs_fragment_entry **fragment_table,
|
||||
squashfs_inode **inode_lookup_table)
|
||||
{
|
||||
unsigned char *inode_table = NULL, *directory_table = NULL;
|
||||
long long start = sBlk->inode_table_start;
|
||||
long long end = sBlk->directory_table_start;
|
||||
long long root_inode_start = start +
|
||||
SQUASHFS_INODE_BLK(sBlk->root_inode);
|
||||
unsigned int root_inode_offset =
|
||||
SQUASHFS_INODE_OFFSET(sBlk->root_inode);
|
||||
unsigned int root_inode_block;
|
||||
union squashfs_inode_header inode;
|
||||
unsigned int *id_table = NULL;
|
||||
int res;
|
||||
|
||||
printf("Scanning existing filesystem...\n");
|
||||
|
||||
if(get_xattrs(fd, sBlk) == 0)
|
||||
goto error;
|
||||
|
||||
if(sBlk->fragments > 0) {
|
||||
*fragment_table = read_fragment_table(fd, sBlk);
|
||||
if(*fragment_table == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(sBlk->lookup_table_start != SQUASHFS_INVALID_BLK) {
|
||||
*inode_lookup_table = read_inode_lookup_table(fd, sBlk);
|
||||
if(*inode_lookup_table == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
id_table = read_id_table(fd, sBlk);
|
||||
if(id_table == NULL)
|
||||
goto error;
|
||||
|
||||
inode_table = scan_inode_table(fd, start, end, root_inode_start,
|
||||
root_inode_offset, sBlk, &inode, &root_inode_block,
|
||||
root_inode_size, uncompressed_file, uncompressed_directory,
|
||||
file_count, sym_count, dev_count, dir_count, fifo_count,
|
||||
sock_count, id_table);
|
||||
if(inode_table == NULL)
|
||||
goto error;
|
||||
|
||||
*uncompressed_inode = root_inode_block;
|
||||
|
||||
if(inode.base.inode_type == SQUASHFS_DIR_TYPE ||
|
||||
inode.base.inode_type == SQUASHFS_LDIR_TYPE) {
|
||||
if(inode.base.inode_type == SQUASHFS_DIR_TYPE) {
|
||||
*inode_dir_start_block = inode.dir.start_block;
|
||||
*inode_dir_offset = inode.dir.offset;
|
||||
*inode_dir_file_size = inode.dir.file_size - 3;
|
||||
*inode_dir_inode_number = inode.dir.inode_number;
|
||||
*inode_dir_parent_inode = inode.dir.parent_inode;
|
||||
} else {
|
||||
*inode_dir_start_block = inode.ldir.start_block;
|
||||
*inode_dir_offset = inode.ldir.offset;
|
||||
*inode_dir_file_size = inode.ldir.file_size - 3;
|
||||
*inode_dir_inode_number = inode.ldir.inode_number;
|
||||
*inode_dir_parent_inode = inode.ldir.parent_inode;
|
||||
}
|
||||
|
||||
directory_table = squashfs_readdir(fd, !root_name,
|
||||
*inode_dir_start_block, *inode_dir_offset,
|
||||
*inode_dir_file_size, last_directory_block, sBlk,
|
||||
push_directory_entry);
|
||||
if(directory_table == NULL)
|
||||
goto error;
|
||||
|
||||
root_inode_start -= start;
|
||||
*cinode_table = malloc(root_inode_start);
|
||||
if(*cinode_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, start, root_inode_start, *cinode_table);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read inode table\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*cdirectory_table = malloc(*last_directory_block);
|
||||
if(*cdirectory_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->directory_table_start,
|
||||
*last_directory_block, *cdirectory_table);
|
||||
if(res == 0) {
|
||||
ERROR("Failed to read directory table\n");
|
||||
ERROR("Filesystem corrupted?\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*data_cache = malloc(root_inode_offset + *root_inode_size);
|
||||
if(*data_cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(*data_cache, inode_table + root_inode_block,
|
||||
root_inode_offset + *root_inode_size);
|
||||
|
||||
*directory_data_cache = malloc(*inode_dir_offset +
|
||||
*inode_dir_file_size);
|
||||
if(*directory_data_cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(*directory_data_cache, directory_table,
|
||||
*inode_dir_offset + *inode_dir_file_size);
|
||||
|
||||
free(id_table);
|
||||
free(inode_table);
|
||||
free(directory_table);
|
||||
return sBlk->inode_table_start;
|
||||
}
|
||||
|
||||
error:
|
||||
free(id_table);
|
||||
free(inode_table);
|
||||
free(directory_table);
|
||||
return 0;
|
||||
}
|
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.h
Normal file
34
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef READ_FS_H
|
||||
#define READ_FS_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_fs.h
|
||||
*
|
||||
*/
|
||||
extern struct compressor *read_super(int, struct squashfs_super_block *,
|
||||
char *);
|
||||
extern long long read_filesystem(char *, int, struct squashfs_super_block *,
|
||||
char **, char **, char **, char **, unsigned int *, unsigned int *,
|
||||
unsigned int *, unsigned int *, unsigned int *, int *, int *, int *, int *,
|
||||
int *, int *, long long *, unsigned int *, unsigned int *, unsigned int *,
|
||||
unsigned int *, void (push_directory_entry)(char *, squashfs_inode, int, int),
|
||||
struct squashfs_fragment_entry **, squashfs_inode **);
|
||||
#endif
|
428
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_xattrs.c
Normal file
428
SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_xattrs.c
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Read a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2010, 2012, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* read_xattrs.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common xattr read code shared between mksquashfs and unsquashfs
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_swap.h"
|
||||
#include "xattr.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int read_fs_bytes(int, long long, int, void *);
|
||||
extern int read_block(int, long long, long long *, int, void *);
|
||||
|
||||
static struct hash_entry {
|
||||
long long start;
|
||||
unsigned int offset;
|
||||
struct hash_entry *next;
|
||||
} *hash_table[65536];
|
||||
|
||||
static struct squashfs_xattr_id *xattr_ids;
|
||||
static void *xattrs = NULL;
|
||||
static long long xattr_table_start;
|
||||
|
||||
/*
|
||||
* Prefix lookup table, storing mapping to/from prefix string and prefix id
|
||||
*/
|
||||
struct prefix prefix_table[] = {
|
||||
{ "user.", SQUASHFS_XATTR_USER },
|
||||
{ "trusted.", SQUASHFS_XATTR_TRUSTED },
|
||||
{ "security.", SQUASHFS_XATTR_SECURITY },
|
||||
{ "", -1 }
|
||||
};
|
||||
|
||||
/*
|
||||
* store mapping from location of compressed block in fs ->
|
||||
* location of uncompressed block in memory
|
||||
*/
|
||||
static void save_xattr_block(long long start, int offset)
|
||||
{
|
||||
struct hash_entry *hash_entry = malloc(sizeof(*hash_entry));
|
||||
int hash = start & 0xffff;
|
||||
|
||||
TRACE("save_xattr_block: start %lld, offset %d\n", start, offset);
|
||||
|
||||
if(hash_entry == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
hash_entry->start = start;
|
||||
hash_entry->offset = offset;
|
||||
hash_entry->next = hash_table[hash];
|
||||
hash_table[hash] = hash_entry;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* map from location of compressed block in fs ->
|
||||
* location of uncompressed block in memory
|
||||
*/
|
||||
static int get_xattr_block(long long start)
|
||||
{
|
||||
int hash = start & 0xffff;
|
||||
struct hash_entry *hash_entry = hash_table[hash];
|
||||
|
||||
for(; hash_entry; hash_entry = hash_entry->next)
|
||||
if(hash_entry->start == start)
|
||||
break;
|
||||
|
||||
TRACE("get_xattr_block: start %lld, offset %d\n", start,
|
||||
hash_entry ? hash_entry->offset : -1);
|
||||
|
||||
return hash_entry ? hash_entry->offset : -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* construct the xattr_list entry from the fs xattr, including
|
||||
* mapping name and prefix into a full name
|
||||
*/
|
||||
static int read_xattr_entry(struct xattr_list *xattr,
|
||||
struct squashfs_xattr_entry *entry, void *name)
|
||||
{
|
||||
int i, len, type = entry->type & XATTR_PREFIX_MASK;
|
||||
|
||||
for(i = 0; prefix_table[i].type != -1; i++)
|
||||
if(prefix_table[i].type == type)
|
||||
break;
|
||||
|
||||
if(prefix_table[i].type == -1) {
|
||||
ERROR("read_xattr_entry: Unrecognised xattr type %d\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(prefix_table[i].prefix);
|
||||
xattr->full_name = malloc(len + entry->size + 1);
|
||||
if(xattr->full_name == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(xattr->full_name, prefix_table[i].prefix, len);
|
||||
memcpy(xattr->full_name + len, name, entry->size);
|
||||
xattr->full_name[len + entry->size] = '\0';
|
||||
xattr->name = xattr->full_name + len;
|
||||
xattr->size = entry->size;
|
||||
xattr->type = type;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read and decompress the xattr id table and the xattr metadata.
|
||||
* This is cached in memory for later use by get_xattr()
|
||||
*/
|
||||
int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk, int flag, long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of ids (id_table.xattr_ids) is 2^32 (unsigned int)
|
||||
* Max size of bytes is 2^32*16 or 2^36
|
||||
* Max indexes is (2^32*16)/8K or 2^23
|
||||
* Max index_bytes is ((2^32*16)/8K)*8 or 2^26 or 64M
|
||||
*/
|
||||
int res, i, indexes, index_bytes;
|
||||
unsigned int ids;
|
||||
long long bytes;
|
||||
long long *index, start, end;
|
||||
struct squashfs_xattr_table id_table;
|
||||
|
||||
TRACE("read_xattrs_from_disk\n");
|
||||
|
||||
if(sBlk->xattr_id_table_start == SQUASHFS_INVALID_BLK)
|
||||
return SQUASHFS_INVALID_BLK;
|
||||
|
||||
/*
|
||||
* Read xattr id table, containing start of xattr metadata and the
|
||||
* number of xattrs in the file system
|
||||
*/
|
||||
res = read_fs_bytes(fd, sBlk->xattr_id_table_start, sizeof(id_table),
|
||||
&id_table);
|
||||
if(res == 0)
|
||||
return 0;
|
||||
|
||||
SQUASHFS_INSWAP_XATTR_TABLE(&id_table);
|
||||
|
||||
/*
|
||||
* Compute index table values
|
||||
*/
|
||||
ids = id_table.xattr_ids;
|
||||
xattr_table_start = id_table.xattr_table_start;
|
||||
index_bytes = SQUASHFS_XATTR_BLOCK_BYTES((long long) ids);
|
||||
indexes = SQUASHFS_XATTR_BLOCKS((long long) ids);
|
||||
|
||||
/*
|
||||
* The size of the index table (index_bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(index_bytes != (sBlk->bytes_used - (sBlk->xattr_id_table_start + sizeof(id_table)))) {
|
||||
ERROR("read_xattrs_from_disk: Bad xattr_ids count in super block\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* id_table.xattr_table_start stores the start of the compressed xattr
|
||||
* metadata blocks. This by definition is also the end of the previous
|
||||
* filesystem table - the id lookup table.
|
||||
*/
|
||||
if(table_start != NULL)
|
||||
*table_start = id_table.xattr_table_start;
|
||||
|
||||
/*
|
||||
* If flag is set then return once we've read the above
|
||||
* table_start. That value is necessary for sanity checking,
|
||||
* but we don't actually want to extract the xattrs, and so
|
||||
* stop here.
|
||||
*/
|
||||
if(flag)
|
||||
return id_table.xattr_ids;
|
||||
|
||||
/*
|
||||
* Allocate and read the index to the xattr id table metadata
|
||||
* blocks
|
||||
*/
|
||||
index = malloc(index_bytes);
|
||||
if(index == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
res = read_fs_bytes(fd, sBlk->xattr_id_table_start + sizeof(id_table),
|
||||
index_bytes, index);
|
||||
if(res ==0)
|
||||
goto failed1;
|
||||
|
||||
SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
|
||||
|
||||
/*
|
||||
* Allocate enough space for the uncompressed xattr id table, and
|
||||
* read and decompress it
|
||||
*/
|
||||
bytes = SQUASHFS_XATTR_BYTES((long long) ids);
|
||||
xattr_ids = malloc(bytes);
|
||||
if(xattr_ids == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, index[i], NULL, expected,
|
||||
((unsigned char *) xattr_ids) +
|
||||
((long long) i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read xattr id table block %d, from 0x%llx, length "
|
||||
"%d\n", i, index[i], length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read xattr id table block %d, "
|
||||
"from 0x%llx, length %d\n", i, index[i],
|
||||
length);
|
||||
goto failed2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and decompress the xattr metadata
|
||||
*
|
||||
* Note the first xattr id table metadata block is immediately after
|
||||
* the last xattr metadata block, so we can use index[0] to work out
|
||||
* the end of the xattr metadata
|
||||
*/
|
||||
start = xattr_table_start;
|
||||
end = index[0];
|
||||
for(i = 0; start < end; i++) {
|
||||
int length;
|
||||
xattrs = realloc(xattrs, (i + 1) * SQUASHFS_METADATA_SIZE);
|
||||
if(xattrs == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
/* store mapping from location of compressed block in fs ->
|
||||
* location of uncompressed block in memory */
|
||||
save_xattr_block(start, i * SQUASHFS_METADATA_SIZE);
|
||||
|
||||
length = read_block(fd, start, &start, 0,
|
||||
((unsigned char *) xattrs) +
|
||||
(i * SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read xattr block %d, length %d\n", i, length);
|
||||
if(length == 0) {
|
||||
ERROR("Failed to read xattr block %d\n", i);
|
||||
goto failed3;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not the last metadata block in the xattr metadata
|
||||
* then it should be SQUASHFS_METADATA_SIZE in size.
|
||||
* Note, we can't use expected in read_block() above for this
|
||||
* because we don't know if this is the last block until
|
||||
* after reading.
|
||||
*/
|
||||
if(start != end && length != SQUASHFS_METADATA_SIZE) {
|
||||
ERROR("Xattr block %d should be %d bytes in length, "
|
||||
"it is %d bytes\n", i, SQUASHFS_METADATA_SIZE,
|
||||
length);
|
||||
goto failed3;
|
||||
}
|
||||
}
|
||||
|
||||
/* swap if necessary the xattr id entries */
|
||||
for(i = 0; i < ids; i++)
|
||||
SQUASHFS_INSWAP_XATTR_ID(&xattr_ids[i]);
|
||||
|
||||
free(index);
|
||||
|
||||
return ids;
|
||||
|
||||
failed3:
|
||||
free(xattrs);
|
||||
failed2:
|
||||
free(xattr_ids);
|
||||
failed1:
|
||||
free(index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void free_xattr(struct xattr_list *xattr_list, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < count; i++)
|
||||
free(xattr_list[i].full_name);
|
||||
|
||||
free(xattr_list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Construct and return the list of xattr name:value pairs for the passed xattr
|
||||
* id
|
||||
*
|
||||
* There are two users for get_xattr(), Mksquashfs uses it to read the
|
||||
* xattrs from the filesystem on appending, and Unsquashfs uses it
|
||||
* to retrieve the xattrs for writing to disk.
|
||||
*
|
||||
* Unfortunately, the two users disagree on what to do with unknown
|
||||
* xattr prefixes, Mksquashfs wants to treat this as fatal otherwise
|
||||
* this will cause xattrs to be be lost on appending. Unsquashfs
|
||||
* on the otherhand wants to retrieve the xattrs which are known and
|
||||
* to ignore the rest, this allows Unsquashfs to cope more gracefully
|
||||
* with future versions which may have unknown xattrs, as long as the
|
||||
* general xattr structure is adhered to, Unsquashfs should be able
|
||||
* to safely ignore unknown xattrs, and to write the ones it knows about,
|
||||
* this is better than completely refusing to retrieve all the xattrs.
|
||||
*
|
||||
* So return an error flag if any unrecognised types were found.
|
||||
*/
|
||||
struct xattr_list *get_xattr(int i, unsigned int *count, int *failed)
|
||||
{
|
||||
long long start;
|
||||
struct xattr_list *xattr_list = NULL;
|
||||
unsigned int offset;
|
||||
void *xptr;
|
||||
int j, n, res = 1;
|
||||
|
||||
TRACE("get_xattr\n");
|
||||
|
||||
if(xattr_ids[i].count == 0) {
|
||||
ERROR("get_xattr: xattr count unexpectedly 0 - corrupt fs?\n");
|
||||
*failed = TRUE;
|
||||
*count = 0;
|
||||
return NULL;
|
||||
} else
|
||||
*failed = FALSE;
|
||||
|
||||
start = SQUASHFS_XATTR_BLK(xattr_ids[i].xattr) + xattr_table_start;
|
||||
offset = SQUASHFS_XATTR_OFFSET(xattr_ids[i].xattr);
|
||||
xptr = xattrs + get_xattr_block(start) + offset;
|
||||
|
||||
TRACE("get_xattr: xattr_id %d, count %d, start %lld, offset %d\n", i,
|
||||
xattr_ids[i].count, start, offset);
|
||||
|
||||
for(j = 0, n = 0; n < xattr_ids[i].count; n++) {
|
||||
struct squashfs_xattr_entry entry;
|
||||
struct squashfs_xattr_val val;
|
||||
|
||||
if(res != 0) {
|
||||
xattr_list = realloc(xattr_list, (j + 1) *
|
||||
sizeof(struct xattr_list));
|
||||
if(xattr_list == NULL)
|
||||
MEM_ERROR();
|
||||
}
|
||||
|
||||
SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry);
|
||||
xptr += sizeof(entry);
|
||||
|
||||
res = read_xattr_entry(&xattr_list[j], &entry, xptr);
|
||||
if(res == 0) {
|
||||
/* unknown type, skip, and set error flag */
|
||||
xptr += entry.size;
|
||||
SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
|
||||
xptr += sizeof(val) + val.vsize;
|
||||
*failed = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
xptr += entry.size;
|
||||
|
||||
TRACE("get_xattr: xattr %d, type %d, size %d, name %s\n", j,
|
||||
entry.type, entry.size, xattr_list[j].full_name);
|
||||
|
||||
if(entry.type & SQUASHFS_XATTR_VALUE_OOL) {
|
||||
long long xattr;
|
||||
void *ool_xptr;
|
||||
|
||||
xptr += sizeof(val);
|
||||
SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1);
|
||||
xptr += sizeof(xattr);
|
||||
start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start;
|
||||
offset = SQUASHFS_XATTR_OFFSET(xattr);
|
||||
ool_xptr = xattrs + get_xattr_block(start) + offset;
|
||||
SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val);
|
||||
xattr_list[j].value = ool_xptr + sizeof(val);
|
||||
} else {
|
||||
SQUASHFS_SWAP_XATTR_VAL(xptr, &val);
|
||||
xattr_list[j].value = xptr + sizeof(val);
|
||||
xptr += sizeof(val) + val.vsize;
|
||||
}
|
||||
|
||||
TRACE("get_xattr: xattr %d, vsize %d\n", j, val.vsize);
|
||||
|
||||
xattr_list[j++].vsize = val.vsize;
|
||||
}
|
||||
|
||||
*count = j;
|
||||
return xattr_list;
|
||||
}
|
168
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.c
Normal file
168
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* restore.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "caches-queues-lists.h"
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
#include "info.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
extern pthread_t reader_thread, writer_thread, main_thread, order_thread;
|
||||
extern pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
|
||||
extern struct queue *to_deflate, *to_writer, *to_frag, *to_process_frag;
|
||||
extern struct seq_queue *to_main, *to_order;
|
||||
extern void restorefs();
|
||||
extern int processors;
|
||||
extern int reproducible;
|
||||
|
||||
static int interrupted = 0;
|
||||
static pthread_t restore_thread;
|
||||
|
||||
void *restore_thrd(void *arg)
|
||||
{
|
||||
sigset_t sigmask, old_mask;
|
||||
int i, sig;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGINT);
|
||||
sigaddset(&sigmask, SIGTERM);
|
||||
sigaddset(&sigmask, SIGUSR1);
|
||||
pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask);
|
||||
|
||||
while(1) {
|
||||
sigwait(&sigmask, &sig);
|
||||
|
||||
if((sig == SIGINT || sig == SIGTERM) && !interrupted) {
|
||||
ERROR("Interrupting will restore original "
|
||||
"filesystem!\n");
|
||||
ERROR("Interrupt again to quit\n");
|
||||
interrupted = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* kill main thread/worker threads and restore */
|
||||
set_progressbar_state(FALSE);
|
||||
disable_info();
|
||||
|
||||
/* first kill the reader thread */
|
||||
pthread_cancel(reader_thread);
|
||||
pthread_join(reader_thread, NULL);
|
||||
|
||||
/*
|
||||
* then flush the reader to deflator thread(s) output queue.
|
||||
* The deflator thread(s) will idle
|
||||
*/
|
||||
queue_flush(to_deflate);
|
||||
|
||||
/* now kill the deflator thread(s) */
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_cancel(deflator_thread[i]);
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_join(deflator_thread[i], NULL);
|
||||
|
||||
/*
|
||||
* then flush the reader to process fragment thread(s) output
|
||||
* queue. The process fragment thread(s) will idle
|
||||
*/
|
||||
queue_flush(to_process_frag);
|
||||
|
||||
/* now kill the process fragment thread(s) */
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_cancel(frag_thread[i]);
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_join(frag_thread[i], NULL);
|
||||
|
||||
/*
|
||||
* then flush the reader/deflator/process fragment to main
|
||||
* thread output queue. The main thread will idle
|
||||
*/
|
||||
seq_queue_flush(to_main);
|
||||
|
||||
/* now kill the main thread */
|
||||
pthread_cancel(main_thread);
|
||||
pthread_join(main_thread, NULL);
|
||||
|
||||
/* then flush the main thread to fragment deflator thread(s)
|
||||
* queue. The fragment deflator thread(s) will idle
|
||||
*/
|
||||
queue_flush(to_frag);
|
||||
|
||||
/* now kill the fragment deflator thread(s) */
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_cancel(frag_deflator_thread[i]);
|
||||
for(i = 0; i < processors; i++)
|
||||
pthread_join(frag_deflator_thread[i], NULL);
|
||||
|
||||
if(reproducible) {
|
||||
/* then flush the fragment deflator_threads(s)
|
||||
* to frag orderer thread. The frag orderer
|
||||
* thread will idle
|
||||
*/
|
||||
seq_queue_flush(to_order);
|
||||
|
||||
/* now kill the frag orderer thread */
|
||||
pthread_cancel(order_thread);
|
||||
pthread_join(order_thread, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* then flush the main thread/fragment deflator thread(s)
|
||||
* to writer thread queue. The writer thread will idle
|
||||
*/
|
||||
queue_flush(to_writer);
|
||||
|
||||
/* now kill the writer thread */
|
||||
pthread_cancel(writer_thread);
|
||||
pthread_join(writer_thread, NULL);
|
||||
|
||||
TRACE("All threads cancelled\n");
|
||||
|
||||
restorefs();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pthread_t *init_restore_thread()
|
||||
{
|
||||
pthread_create(&restore_thread, NULL, restore_thrd, NULL);
|
||||
return &restore_thread;
|
||||
}
|
28
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.h
Normal file
28
SQUASHFS/squashfs-tools-4.4/squashfs-tools/restore.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef RESTORE_H
|
||||
#define RESTORE_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* restore.h
|
||||
*/
|
||||
|
||||
extern pthread_t *init_restore_thread();
|
||||
#endif
|
363
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.c
Normal file
363
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
|
||||
* 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* sort.c
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define MAX_LINE 16384
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "sort.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
|
||||
int mkisofs_style = -1;
|
||||
|
||||
struct sort_info {
|
||||
dev_t st_dev;
|
||||
ino_t st_ino;
|
||||
int priority;
|
||||
struct sort_info *next;
|
||||
};
|
||||
|
||||
struct sort_info *sort_info_list[65536];
|
||||
|
||||
struct priority_entry *priority_list[65536];
|
||||
|
||||
extern int silent;
|
||||
extern void write_file(squashfs_inode *inode, struct dir_ent *dir_ent,
|
||||
int *c_size);
|
||||
extern char *pathname(struct dir_ent *dir_ent);
|
||||
|
||||
|
||||
void add_priority_list(struct dir_ent *dir, int priority)
|
||||
{
|
||||
struct priority_entry *new_priority_entry;
|
||||
|
||||
priority += 32768;
|
||||
new_priority_entry = malloc(sizeof(struct priority_entry));
|
||||
if(new_priority_entry == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
new_priority_entry->dir = dir;;
|
||||
new_priority_entry->next = priority_list[priority];
|
||||
priority_list[priority] = new_priority_entry;
|
||||
}
|
||||
|
||||
|
||||
int get_priority(char *filename, struct stat *buf, int priority)
|
||||
{
|
||||
int hash = buf->st_ino & 0xffff;
|
||||
struct sort_info *s;
|
||||
|
||||
for(s = sort_info_list[hash]; s; s = s->next)
|
||||
if((s->st_dev == buf->st_dev) && (s->st_ino == buf->st_ino)) {
|
||||
TRACE("returning priority %d (%s)\n", s->priority,
|
||||
filename);
|
||||
return s->priority;
|
||||
}
|
||||
TRACE("returning priority %d (%s)\n", priority, filename);
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
#define ADD_ENTRY(buf, priority) {\
|
||||
int hash = buf.st_ino & 0xffff;\
|
||||
struct sort_info *s;\
|
||||
if((s = malloc(sizeof(struct sort_info))) == NULL) \
|
||||
MEM_ERROR(); \
|
||||
s->st_dev = buf.st_dev;\
|
||||
s->st_ino = buf.st_ino;\
|
||||
s->priority = priority;\
|
||||
s->next = sort_info_list[hash];\
|
||||
sort_info_list[hash] = s;\
|
||||
}
|
||||
int add_sort_list(char *path, int priority, int source, char *source_path[])
|
||||
{
|
||||
int i, n;
|
||||
struct stat buf;
|
||||
|
||||
TRACE("add_sort_list: filename %s, priority %d\n", path, priority);
|
||||
if(strlen(path) > 1 && strcmp(path + strlen(path) - 2, "/*") == 0)
|
||||
path[strlen(path) - 2] = '\0';
|
||||
|
||||
TRACE("add_sort_list: filename %s, priority %d\n", path, priority);
|
||||
re_read:
|
||||
if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
|
||||
strncmp(path, "../", 3) == 0 || mkisofs_style == 1) {
|
||||
if(lstat(path, &buf) == -1)
|
||||
goto error;
|
||||
TRACE("adding filename %s, priority %d, st_dev %d, st_ino "
|
||||
"%lld\n", path, priority, (int) buf.st_dev,
|
||||
(long long) buf.st_ino);
|
||||
ADD_ENTRY(buf, priority);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for(i = 0, n = 0; i < source; i++) {
|
||||
char *filename;
|
||||
int res = asprintf(&filename, "%s/%s", source_path[i], path);
|
||||
if(res == -1)
|
||||
BAD_ERROR("asprintf failed in add_sort_list\n");
|
||||
res = lstat(filename, &buf);
|
||||
free(filename);
|
||||
if(res == -1) {
|
||||
if(!(errno == ENOENT || errno == ENOTDIR))
|
||||
goto error;
|
||||
continue;
|
||||
}
|
||||
ADD_ENTRY(buf, priority);
|
||||
n ++;
|
||||
}
|
||||
|
||||
if(n == 0 && mkisofs_style == -1 && lstat(path, &buf) != -1) {
|
||||
ERROR("WARNING: Mkisofs style sortlist detected! This is "
|
||||
"supported but please\n");
|
||||
ERROR("convert to mksquashfs style sortlist! A sortlist entry");
|
||||
ERROR(" should be\neither absolute (starting with ");
|
||||
ERROR("'/') start with './' or '../' (taken to be\nrelative to "
|
||||
"$PWD), otherwise it ");
|
||||
ERROR("is assumed the entry is relative to one\nof the source "
|
||||
"directories, i.e. with ");
|
||||
ERROR("\"mksquashfs test test.sqsh\",\nthe sortlist ");
|
||||
ERROR("entry \"file\" is assumed to be inside the directory "
|
||||
"test.\n\n");
|
||||
mkisofs_style = 1;
|
||||
goto re_read;
|
||||
}
|
||||
|
||||
mkisofs_style = 0;
|
||||
|
||||
if(n == 1)
|
||||
return TRUE;
|
||||
if(n > 1) {
|
||||
ERROR(" Ambiguous sortlist entry \"%s\"\n\nIt maps to more "
|
||||
"than one source entry! Please use an absolute path."
|
||||
"\n", path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
error:
|
||||
ERROR_START("Cannot stat sortlist entry \"%s\"\n", path);
|
||||
ERROR("This is probably because you're using the wrong file\n");
|
||||
ERROR("path relative to the source directories.");
|
||||
ERROR_EXIT(" Ignoring");
|
||||
/*
|
||||
* Historical note
|
||||
* Failure to stat a sortlist entry is deliberately ignored, even
|
||||
* though it is an error. Squashfs release 2.2 changed the behaviour
|
||||
* to treat it as a fatal error, but it was changed back to
|
||||
* the original behaviour to ignore it in release 2.2-r2 following
|
||||
* feedback from users at the time.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void generate_file_priorities(struct dir_info *dir, int priority,
|
||||
struct stat *buf)
|
||||
{
|
||||
struct dir_ent *dir_ent = dir->list;
|
||||
|
||||
priority = get_priority(dir->pathname, buf, priority);
|
||||
|
||||
for(; dir_ent; dir_ent = dir_ent->next) {
|
||||
struct stat *buf = &dir_ent->inode->buf;
|
||||
if(dir_ent->inode->root_entry)
|
||||
continue;
|
||||
|
||||
switch(buf->st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
add_priority_list(dir_ent,
|
||||
get_priority(pathname(dir_ent), buf,
|
||||
priority));
|
||||
break;
|
||||
case S_IFDIR:
|
||||
generate_file_priorities(dir_ent->dir,
|
||||
priority, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int read_sort_file(char *filename, int source, char *source_path[])
|
||||
{
|
||||
FILE *fd;
|
||||
char line_buffer[MAX_LINE + 1]; /* overflow safe */
|
||||
char sort_filename[MAX_LINE + 1]; /* overflow safe */
|
||||
char *line, *name;
|
||||
int n, priority, res;
|
||||
|
||||
if((fd = fopen(filename, "r")) == NULL) {
|
||||
ERROR("Failed to open sort file \"%s\" because %s\n",
|
||||
filename, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while(fgets(line = line_buffer, MAX_LINE + 1, fd) != NULL) {
|
||||
int len = strlen(line);
|
||||
|
||||
if(len == MAX_LINE && line[len - 1] != '\n') {
|
||||
/* line too large */
|
||||
ERROR("Line too long when reading "
|
||||
"sort file \"%s\", larger than %d "
|
||||
"bytes\n", filename, MAX_LINE);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove '\n' terminator if it exists (the last line
|
||||
* in the file may not be '\n' terminated)
|
||||
*/
|
||||
if(len && line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
|
||||
/* Skip any leading whitespace */
|
||||
while(isspace(*line))
|
||||
line ++;
|
||||
|
||||
/* if comment line, skip */
|
||||
if(*line == '#')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Scan for filename, don't use sscanf() and "%s" because
|
||||
* that can't handle filenames with spaces
|
||||
*/
|
||||
for(name = sort_filename; !isspace(*line) && *line != '\0';) {
|
||||
if(*line == '\\') {
|
||||
line ++;
|
||||
if (*line == '\0')
|
||||
break;
|
||||
}
|
||||
*name ++ = *line ++;
|
||||
}
|
||||
*name = '\0';
|
||||
|
||||
/*
|
||||
* if filename empty, then line was empty of anything but
|
||||
* whitespace or a backslash character. Skip empy lines
|
||||
*/
|
||||
if(sort_filename[0] == '\0')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Scan the rest of the line, we expect a decimal number
|
||||
* which is the filename priority
|
||||
*/
|
||||
errno = 0;
|
||||
res = sscanf(line, "%d%n", &priority, &n);
|
||||
|
||||
if((res < 1 || errno) && errno != ERANGE) {
|
||||
if(errno == 0)
|
||||
/* No error, assume EOL or match failure */
|
||||
ERROR("Sort file \"%s\", can't find priority "
|
||||
"in entry \"%s\", EOL or match "
|
||||
"failure\n", filename, line_buffer);
|
||||
else
|
||||
/* Some other failure not ERANGE */
|
||||
ERROR("Sscanf failed reading sort file \"%s\" "
|
||||
"because %s\n", filename,
|
||||
strerror(errno));
|
||||
goto failed;
|
||||
} else if((errno == ERANGE) ||
|
||||
(priority < -32768 || priority > 32767)) {
|
||||
ERROR("Sort file \"%s\", entry \"%s\" has priority "
|
||||
"outside range of -32767:32768.\n", filename,
|
||||
line_buffer);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Skip any trailing whitespace */
|
||||
line += n;
|
||||
while(isspace(*line))
|
||||
line ++;
|
||||
|
||||
if(*line != '\0') {
|
||||
ERROR("Sort file \"%s\", trailing characters after "
|
||||
"priority in entry \"%s\"\n", filename,
|
||||
line_buffer);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
res = add_sort_list(sort_filename, priority, source,
|
||||
source_path);
|
||||
if(res == FALSE)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(ferror(fd)) {
|
||||
ERROR("Reading sort file \"%s\" failed because %s\n", filename,
|
||||
strerror(errno));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
fclose(fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void sort_files_and_write(struct dir_info *dir)
|
||||
{
|
||||
int i;
|
||||
struct priority_entry *entry;
|
||||
squashfs_inode inode;
|
||||
int duplicate_file;
|
||||
|
||||
for(i = 65535; i >= 0; i--)
|
||||
for(entry = priority_list[i]; entry; entry = entry->next) {
|
||||
TRACE("%d: %s\n", i - 32768, pathname(entry->dir));
|
||||
if(entry->dir->inode->inode == SQUASHFS_INVALID_BLK) {
|
||||
write_file(&inode, entry->dir, &duplicate_file);
|
||||
INFO("file %s, uncompressed size %lld bytes %s"
|
||||
"\n", pathname(entry->dir),
|
||||
(long long)
|
||||
entry->dir->inode->buf.st_size,
|
||||
duplicate_file ? "DUPLICATE" : "");
|
||||
entry->dir->inode->inode = inode;
|
||||
entry->dir->inode->type = SQUASHFS_FILE_TYPE;
|
||||
} else
|
||||
INFO("file %s, uncompressed size %lld bytes "
|
||||
"LINK\n", pathname(entry->dir),
|
||||
(long long)
|
||||
entry->dir->inode->buf.st_size);
|
||||
}
|
||||
}
|
37
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.h
Normal file
37
SQUASHFS/squashfs-tools-4.4/squashfs-tools/sort.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef SORT_H
|
||||
#define SORT_H
|
||||
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* sort.h
|
||||
*/
|
||||
|
||||
struct priority_entry {
|
||||
struct dir_ent *dir;
|
||||
struct priority_entry *next;
|
||||
};
|
||||
|
||||
extern int read_sort_file(char *, int, char *[]);
|
||||
extern void sort_files_and_write(struct dir_info *);
|
||||
extern void generate_file_priorities(struct dir_info *, int priority,
|
||||
struct stat *);
|
||||
extern struct priority_entry *priority_list[65536];
|
||||
#endif
|
834
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_compat.h
Normal file
834
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_compat.h
Normal file
|
@ -0,0 +1,834 @@
|
|||
#ifndef SQUASHFS_COMPAT
|
||||
#define SQUASHFS_COMPAT
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_compat.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* definitions for structures on disk - layout 3.x
|
||||
*/
|
||||
|
||||
#define SQUASHFS_CHECK 2
|
||||
#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_CHECK)
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_UIDS 256
|
||||
#define SQUASHFS_GUIDS 255
|
||||
|
||||
struct squashfs_super_block_3 {
|
||||
unsigned int s_magic;
|
||||
unsigned int inodes;
|
||||
unsigned int bytes_used_2;
|
||||
unsigned int uid_start_2;
|
||||
unsigned int guid_start_2;
|
||||
unsigned int inode_table_start_2;
|
||||
unsigned int directory_table_start_2;
|
||||
unsigned int s_major:16;
|
||||
unsigned int s_minor:16;
|
||||
unsigned int block_size_1:16;
|
||||
unsigned int block_log:16;
|
||||
unsigned int flags:8;
|
||||
unsigned int no_uids:8;
|
||||
unsigned int no_guids:8;
|
||||
int mkfs_time /* time of filesystem creation */;
|
||||
squashfs_inode root_inode;
|
||||
unsigned int block_size;
|
||||
unsigned int fragments;
|
||||
unsigned int fragment_table_start_2;
|
||||
long long bytes_used;
|
||||
long long uid_start;
|
||||
long long guid_start;
|
||||
long long inode_table_start;
|
||||
long long directory_table_start;
|
||||
long long fragment_table_start;
|
||||
long long lookup_table_start;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_index_3 {
|
||||
unsigned int index;
|
||||
unsigned int start_block;
|
||||
unsigned char size;
|
||||
unsigned char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_base_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
squashfs_block start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_lreg_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
squashfs_block start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
long long file_size;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
unsigned int start_block;
|
||||
unsigned int parent_inode;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ldir_inode_header_3 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12;
|
||||
unsigned int uid:8;
|
||||
unsigned int guid:8;
|
||||
int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size:27;
|
||||
unsigned int offset:13;
|
||||
unsigned int start_block;
|
||||
unsigned int i_count:16;
|
||||
unsigned int parent_inode;
|
||||
struct squashfs_dir_index_3 index[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_3 {
|
||||
struct squashfs_base_inode_header_3 base;
|
||||
struct squashfs_dev_inode_header_3 dev;
|
||||
struct squashfs_symlink_inode_header_3 symlink;
|
||||
struct squashfs_reg_inode_header_3 reg;
|
||||
struct squashfs_lreg_inode_header_3 lreg;
|
||||
struct squashfs_dir_inode_header_3 dir;
|
||||
struct squashfs_ldir_inode_header_3 ldir;
|
||||
struct squashfs_ipc_inode_header_3 ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry_3 {
|
||||
unsigned int offset:13;
|
||||
unsigned int type:3;
|
||||
unsigned int size:8;
|
||||
int inode_number:16;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_header_3 {
|
||||
unsigned int count:8;
|
||||
unsigned int start_block;
|
||||
unsigned int inode_number;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_fragment_entry_3 {
|
||||
long long start_block;
|
||||
unsigned int size;
|
||||
unsigned int pending;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
typedef struct squashfs_super_block_3 squashfs_super_block_3;
|
||||
typedef struct squashfs_dir_index_3 squashfs_dir_index_3;
|
||||
typedef struct squashfs_base_inode_header_3 squashfs_base_inode_header_3;
|
||||
typedef struct squashfs_ipc_inode_header_3 squashfs_ipc_inode_header_3;
|
||||
typedef struct squashfs_dev_inode_header_3 squashfs_dev_inode_header_3;
|
||||
typedef struct squashfs_symlink_inode_header_3 squashfs_symlink_inode_header_3;
|
||||
typedef struct squashfs_reg_inode_header_3 squashfs_reg_inode_header_3;
|
||||
typedef struct squashfs_lreg_inode_header_3 squashfs_lreg_inode_header_3;
|
||||
typedef struct squashfs_dir_inode_header_3 squashfs_dir_inode_header_3;
|
||||
typedef struct squashfs_ldir_inode_header_3 squashfs_ldir_inode_header_3;
|
||||
typedef struct squashfs_dir_entry_3 squashfs_dir_entry_3;
|
||||
typedef struct squashfs_dir_header_3 squashfs_dir_header_3;
|
||||
typedef struct squashfs_fragment_entry_3 squashfs_fragment_entry_3;
|
||||
|
||||
/*
|
||||
* macros to convert each packed bitfield structure from little endian to big
|
||||
* endian and vice versa. These are needed when creating or using a filesystem
|
||||
* on a machine with different byte ordering to the target architecture.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SQUASHFS_SWAP_START \
|
||||
int bits;\
|
||||
int b_pos;\
|
||||
unsigned long long val;\
|
||||
unsigned char *s;\
|
||||
unsigned char *d;
|
||||
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block_3));\
|
||||
SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
|
||||
SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
|
||||
SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
|
||||
SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
|
||||
SQUASHFS_SWAP((s)->flags, d, 288, 8);\
|
||||
SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
|
||||
SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
|
||||
SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
|
||||
SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
|
||||
SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
|
||||
SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
|
||||
SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
|
||||
SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
|
||||
SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
|
||||
SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
|
||||
SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
|
||||
SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
|
||||
SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, n)\
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 24, 8);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_3(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_ipc_inode_header_3))\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_3)); \
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_lreg_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 224, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 147, 13);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
|
||||
SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \
|
||||
sizeof(struct squashfs_ldir_inode_header_3));\
|
||||
SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 155, 13);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
|
||||
SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
|
||||
SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INDEX_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_3));\
|
||||
SQUASHFS_SWAP((s)->index, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->size, d, 64, 8);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_HEADER_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_3));\
|
||||
SQUASHFS_SWAP((s)->count, d, 0, 8);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_3));\
|
||||
SQUASHFS_SWAP((s)->offset, d, 0, 13);\
|
||||
SQUASHFS_SWAP((s)->type, d, 13, 3);\
|
||||
SQUASHFS_SWAP((s)->size, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_INODE_T_3(s, d) SQUASHFS_SWAP_LONG_LONGS_3(s, d, 1)
|
||||
|
||||
#define SQUASHFS_SWAP_SHORTS_3(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 2);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
16)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_INTS_3(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 4);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
32)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LONG_LONGS_3(s, d, n) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * 8);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
64)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
|
||||
int entry;\
|
||||
int bit_position;\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, n * bits / 8);\
|
||||
for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
|
||||
bits)\
|
||||
SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES_3(s, d, n) SQUASHFS_SWAP_LONG_LONGS_3(s, d, n)
|
||||
#define SQUASHFS_SWAP_LOOKUP_BLOCKS_3(s, d, n) SQUASHFS_SWAP_LONG_LONGS_3(s, d, n)
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY_3(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_3));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
|
||||
SQUASHFS_SWAP((s)->size, d, 64, 32);\
|
||||
}
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES_3(A) ((A) * sizeof(struct squashfs_fragment_entry_3))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_3(A) (SQUASHFS_FRAGMENT_BYTES_3(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET_3(A) (SQUASHFS_FRAGMENT_BYTES_3(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES_3(A) ((SQUASHFS_FRAGMENT_BYTES_3(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES_3(A) (SQUASHFS_FRAGMENT_INDEXES_3(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* inode lookup table defines */
|
||||
#define SQUASHFS_LOOKUP_BYTES_3(A) ((A) * sizeof(squashfs_inode))
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_3(A) (SQUASHFS_LOOKUP_BYTES_3(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_OFFSET_3(A) (SQUASHFS_LOOKUP_BYTES_3(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCKS_3(A) ((SQUASHFS_LOOKUP_BYTES_3(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_BYTES_3(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/*
|
||||
* definitions for structures on disk - layout 1.x
|
||||
*/
|
||||
#define SQUASHFS_TYPES 5
|
||||
#define SQUASHFS_IPC_TYPE 0
|
||||
|
||||
struct squashfs_base_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int type:4;
|
||||
unsigned int offset:4;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
int mtime;
|
||||
unsigned int start_block;
|
||||
unsigned int file_size:32;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_1 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:4; /* index into uid table */
|
||||
unsigned int guid:4; /* index into guid table */
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
int mtime;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_1 {
|
||||
struct squashfs_base_inode_header_1 base;
|
||||
struct squashfs_dev_inode_header_1 dev;
|
||||
struct squashfs_symlink_inode_header_1 symlink;
|
||||
struct squashfs_reg_inode_header_1 reg;
|
||||
struct squashfs_dir_inode_header_1 dir;
|
||||
struct squashfs_ipc_inode_header_1 ipc;
|
||||
};
|
||||
|
||||
typedef struct squashfs_dir_index_1 squashfs_dir_index_1;
|
||||
typedef struct squashfs_base_inode_header_1 squashfs_base_inode_header_1;
|
||||
typedef struct squashfs_ipc_inode_header_1 squashfs_ipc_inode_header_1;
|
||||
typedef struct squashfs_dev_inode_header_1 squashfs_dev_inode_header_1;
|
||||
typedef struct squashfs_symlink_inode_header_1 squashfs_symlink_inode_header_1;
|
||||
typedef struct squashfs_reg_inode_header_1 squashfs_reg_inode_header_1;
|
||||
typedef struct squashfs_dir_inode_header_1 squashfs_dir_inode_header_1;
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 4);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 20, 4);
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_ipc_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->type, d, 24, 4);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 28, 4);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_1));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 43, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
|
||||
}
|
||||
|
||||
/*
|
||||
* definitions for structures on disk - layout 2.x
|
||||
*/
|
||||
struct squashfs_dir_index_2 {
|
||||
unsigned int index:27;
|
||||
unsigned int start_block:29;
|
||||
unsigned char size;
|
||||
unsigned char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_base_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ipc_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dev_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned short rdev;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_symlink_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned short symlink_size;
|
||||
char symlink[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_reg_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
int mtime;
|
||||
unsigned int start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size:32;
|
||||
unsigned short block_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int file_size:19;
|
||||
unsigned int offset:13;
|
||||
int mtime;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_ldir_inode_header_2 {
|
||||
unsigned int inode_type:4;
|
||||
unsigned int mode:12; /* protection */
|
||||
unsigned int uid:8; /* index into uid table */
|
||||
unsigned int guid:8; /* index into guid table */
|
||||
unsigned int file_size:27;
|
||||
unsigned int offset:13;
|
||||
int mtime;
|
||||
unsigned int start_block:24;
|
||||
unsigned int i_count:16;
|
||||
struct squashfs_dir_index_2 index[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union squashfs_inode_header_2 {
|
||||
struct squashfs_base_inode_header_2 base;
|
||||
struct squashfs_dev_inode_header_2 dev;
|
||||
struct squashfs_symlink_inode_header_2 symlink;
|
||||
struct squashfs_reg_inode_header_2 reg;
|
||||
struct squashfs_dir_inode_header_2 dir;
|
||||
struct squashfs_ldir_inode_header_2 ldir;
|
||||
struct squashfs_ipc_inode_header_2 ipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_header_2 {
|
||||
unsigned int count:8;
|
||||
unsigned int start_block:24;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_dir_entry_2 {
|
||||
unsigned int offset:13;
|
||||
unsigned int type:3;
|
||||
unsigned int size:8;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct squashfs_fragment_entry_2 {
|
||||
unsigned int start_block;
|
||||
unsigned int size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct squashfs_dir_index_2 squashfs_dir_index_2;
|
||||
typedef struct squashfs_base_inode_header_2 squashfs_base_inode_header_2;
|
||||
typedef struct squashfs_ipc_inode_header_2 squashfs_ipc_inode_header_2;
|
||||
typedef struct squashfs_dev_inode_header_2 squashfs_dev_inode_header_2;
|
||||
typedef struct squashfs_symlink_inode_header_2 squashfs_symlink_inode_header_2;
|
||||
typedef struct squashfs_reg_inode_header_2 squashfs_reg_inode_header_2;
|
||||
typedef struct squashfs_lreg_inode_header_2 squashfs_lreg_inode_header_2;
|
||||
typedef struct squashfs_dir_inode_header_2 squashfs_dir_inode_header_2;
|
||||
typedef struct squashfs_ldir_inode_header_2 squashfs_ldir_inode_header_2;
|
||||
typedef struct squashfs_dir_entry_2 squashfs_dir_entry_2;
|
||||
typedef struct squashfs_dir_header_2 squashfs_dir_header_2;
|
||||
typedef struct squashfs_fragment_entry_2 squashfs_fragment_entry_2;
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
|
||||
SQUASHFS_MEMSET(s, d, n);\
|
||||
SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
|
||||
SQUASHFS_SWAP((s)->mode, d, 4, 12);\
|
||||
SQUASHFS_SWAP((s)->uid, d, 16, 8);\
|
||||
SQUASHFS_SWAP((s)->guid, d, 24, 8);\
|
||||
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
|
||||
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_dev_inode_header_2)); \
|
||||
SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_symlink_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_reg_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 128, 32);\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_dir_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 51, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
|
||||
sizeof(struct squashfs_ldir_inode_header_2));\
|
||||
SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
|
||||
SQUASHFS_SWAP((s)->offset, d, 59, 13);\
|
||||
SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
|
||||
SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
|
||||
SQUASHFS_SWAP((s)->index, d, 0, 27);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
|
||||
SQUASHFS_SWAP((s)->size, d, 56, 8);\
|
||||
}
|
||||
#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
|
||||
SQUASHFS_SWAP((s)->count, d, 0, 8);\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
|
||||
SQUASHFS_SWAP((s)->offset, d, 0, 13);\
|
||||
SQUASHFS_SWAP((s)->type, d, 13, 3);\
|
||||
SQUASHFS_SWAP((s)->size, d, 16, 8);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
|
||||
SQUASHFS_SWAP_START\
|
||||
SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
|
||||
SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
|
||||
SQUASHFS_SWAP((s)->size, d, 32, 32);\
|
||||
}
|
||||
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS_3(s, d, n)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES_2(A) ((A) * sizeof(struct squashfs_fragment_entry_2))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
|
||||
sizeof(int))
|
||||
/*
|
||||
* macros used to swap each structure entry, taking into account
|
||||
* bitfields and different bitfield placing conventions on differing architectures
|
||||
*/
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* convert from little endian to big endian */
|
||||
#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos)
|
||||
#else
|
||||
/* convert from big endian to little endian */
|
||||
#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos)
|
||||
#endif
|
||||
|
||||
#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
|
||||
b_pos = pos % 8;\
|
||||
val = 0;\
|
||||
s = (unsigned char *)p + (pos / 8);\
|
||||
d = ((unsigned char *) &val) + 7;\
|
||||
for(bits = 0; bits < (tbits + b_pos); bits += 8) \
|
||||
*d-- = *s++;\
|
||||
value = (val >> (SHIFT));\
|
||||
}
|
||||
#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
|
||||
#endif
|
499
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_fs.h
Normal file
499
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_fs.h
Normal file
|
@ -0,0 +1,499 @@
|
|||
#ifndef SQUASHFS_FS
|
||||
#define SQUASHFS_FS
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012,
|
||||
* 2013, 2014, 2017, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_fs.h
|
||||
*/
|
||||
|
||||
#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
|
||||
#define SQUASHFS_MAJOR 4
|
||||
#define SQUASHFS_MINOR 0
|
||||
#define SQUASHFS_MAGIC 0x73717368
|
||||
#define SQUASHFS_MAGIC_SWAP 0x68737173
|
||||
#define SQUASHFS_START 0
|
||||
|
||||
/* size of metadata (inode and directory) blocks */
|
||||
#define SQUASHFS_METADATA_SIZE 8192
|
||||
#define SQUASHFS_METADATA_LOG 13
|
||||
|
||||
/* default size of data blocks */
|
||||
#define SQUASHFS_FILE_SIZE 131072
|
||||
|
||||
#define SQUASHFS_FILE_MAX_SIZE 1048576
|
||||
#define SQUASHFS_FILE_MAX_LOG 20
|
||||
|
||||
/* Max number of uids and gids */
|
||||
#define SQUASHFS_IDS 65536
|
||||
|
||||
/* Max length of filename (not 255) */
|
||||
#define SQUASHFS_NAME_LEN 256
|
||||
|
||||
/* Max value for directory header count */
|
||||
#define SQUASHFS_DIR_COUNT 256
|
||||
|
||||
#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
|
||||
#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
|
||||
#define SQUASHFS_INVALID_XATTR ((unsigned int) 0xffffffff)
|
||||
#define SQUASHFS_INVALID_BLK ((long long) -1)
|
||||
#define SQUASHFS_USED_BLK ((long long) -2)
|
||||
|
||||
/* Filesystem flags */
|
||||
#define SQUASHFS_NOI 0
|
||||
#define SQUASHFS_NOD 1
|
||||
#define SQUASHFS_CHECK 2
|
||||
#define SQUASHFS_NOF 3
|
||||
#define SQUASHFS_NO_FRAG 4
|
||||
#define SQUASHFS_ALWAYS_FRAG 5
|
||||
#define SQUASHFS_DUPLICATE 6
|
||||
#define SQUASHFS_EXPORT 7
|
||||
#define SQUASHFS_NOX 8
|
||||
#define SQUASHFS_NO_XATTR 9
|
||||
#define SQUASHFS_COMP_OPT 10
|
||||
#define SQUASHFS_NOID 11
|
||||
|
||||
#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOI)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOD)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOF)
|
||||
|
||||
#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_FRAG)
|
||||
|
||||
#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_ALWAYS_FRAG)
|
||||
|
||||
#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_DUPLICATE)
|
||||
|
||||
#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_EXPORT)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_XATTRS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOX)
|
||||
|
||||
#define SQUASHFS_NO_XATTRS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NO_XATTR)
|
||||
|
||||
#define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_COMP_OPT)
|
||||
|
||||
#define SQUASHFS_UNCOMPRESSED_IDS(flags) SQUASHFS_BIT(flags, \
|
||||
SQUASHFS_NOID)
|
||||
|
||||
#define SQUASHFS_MKFLAGS(noi, nod, nof, nox, noid, no_frag, always_frag, \
|
||||
duplicate_checking, exportable, no_xattr, comp_opt) (noi | \
|
||||
(nod << 1) | (nof << 3) | (no_frag << 4) | \
|
||||
(always_frag << 5) | (duplicate_checking << 6) | \
|
||||
(exportable << 7) | (nox << 8) | (no_xattr << 9) | \
|
||||
(comp_opt << 10) | (noid << 11))
|
||||
|
||||
/* Max number of types and file types */
|
||||
#define SQUASHFS_DIR_TYPE 1
|
||||
#define SQUASHFS_FILE_TYPE 2
|
||||
#define SQUASHFS_SYMLINK_TYPE 3
|
||||
#define SQUASHFS_BLKDEV_TYPE 4
|
||||
#define SQUASHFS_CHRDEV_TYPE 5
|
||||
#define SQUASHFS_FIFO_TYPE 6
|
||||
#define SQUASHFS_SOCKET_TYPE 7
|
||||
#define SQUASHFS_LDIR_TYPE 8
|
||||
#define SQUASHFS_LREG_TYPE 9
|
||||
#define SQUASHFS_LSYMLINK_TYPE 10
|
||||
#define SQUASHFS_LBLKDEV_TYPE 11
|
||||
#define SQUASHFS_LCHRDEV_TYPE 12
|
||||
#define SQUASHFS_LFIFO_TYPE 13
|
||||
#define SQUASHFS_LSOCKET_TYPE 14
|
||||
|
||||
/* Xattr types */
|
||||
#define SQUASHFS_XATTR_USER 0
|
||||
#define SQUASHFS_XATTR_TRUSTED 1
|
||||
#define SQUASHFS_XATTR_SECURITY 2
|
||||
#define SQUASHFS_XATTR_VALUE_OOL 256
|
||||
#define SQUASHFS_XATTR_PREFIX_MASK 0xff
|
||||
|
||||
/* Flag whether block is compressed or uncompressed, bit is set if block is
|
||||
* uncompressed */
|
||||
#define SQUASHFS_COMPRESSED_BIT (1 << 15)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
|
||||
(B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
|
||||
|
||||
#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
|
||||
~SQUASHFS_COMPRESSED_BIT_BLOCK)
|
||||
|
||||
#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
|
||||
|
||||
/*
|
||||
* Inode number ops. Inodes consist of a compressed block number, and an
|
||||
* uncompressed offset within that block
|
||||
*/
|
||||
#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
|
||||
|
||||
#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
|
||||
|
||||
#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A)\
|
||||
<< 16) + (B)))
|
||||
|
||||
/* Compute 32 bit VFS inode number from squashfs inode number */
|
||||
#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
|
||||
((b) >> 2) + 1))
|
||||
|
||||
/* Translate between VFS mode and squashfs mode */
|
||||
#define SQUASHFS_MODE(a) ((a) & 0xfff)
|
||||
|
||||
/* fragment and fragment table defines */
|
||||
#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * \
|
||||
sizeof(struct squashfs_fragment_entry))
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* inode lookup table defines */
|
||||
#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode))
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* uid lookup table defines */
|
||||
#define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int))
|
||||
|
||||
#define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
/* xattr id lookup table defines */
|
||||
#define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id))
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\
|
||||
sizeof(long long))
|
||||
|
||||
#define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16))
|
||||
|
||||
#define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff))
|
||||
|
||||
/* cached data constants for filesystem */
|
||||
#define SQUASHFS_CACHED_BLKS 8
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE_LOG 64
|
||||
|
||||
#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
|
||||
(SQUASHFS_MAX_FILE_SIZE_LOG - 2))
|
||||
|
||||
#define SQUASHFS_MARKER_BYTE 0xff
|
||||
|
||||
/* meta index cache */
|
||||
#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
|
||||
#define SQUASHFS_META_ENTRIES 31
|
||||
#define SQUASHFS_META_NUMBER 8
|
||||
#define SQUASHFS_SLOTS 4
|
||||
|
||||
struct meta_entry {
|
||||
long long data_block;
|
||||
unsigned int index_block;
|
||||
unsigned short offset;
|
||||
unsigned short pad;
|
||||
};
|
||||
|
||||
struct meta_index {
|
||||
unsigned int inode_number;
|
||||
unsigned int offset;
|
||||
unsigned short entries;
|
||||
unsigned short skip;
|
||||
unsigned short locked;
|
||||
unsigned short pad;
|
||||
struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* definitions for structures on disk
|
||||
*/
|
||||
|
||||
typedef long long squashfs_block;
|
||||
typedef long long squashfs_inode;
|
||||
|
||||
#define ZLIB_COMPRESSION 1
|
||||
#define LZMA_COMPRESSION 2
|
||||
#define LZO_COMPRESSION 3
|
||||
#define XZ_COMPRESSION 4
|
||||
#define LZ4_COMPRESSION 5
|
||||
#define ZSTD_COMPRESSION 6
|
||||
|
||||
struct squashfs_super_block {
|
||||
unsigned int s_magic;
|
||||
unsigned int inodes;
|
||||
unsigned int mkfs_time /* time of filesystem creation */;
|
||||
unsigned int block_size;
|
||||
unsigned int fragments;
|
||||
unsigned short compression;
|
||||
unsigned short block_log;
|
||||
unsigned short flags;
|
||||
unsigned short no_ids;
|
||||
unsigned short s_major;
|
||||
unsigned short s_minor;
|
||||
squashfs_inode root_inode;
|
||||
long long bytes_used;
|
||||
long long id_table_start;
|
||||
long long xattr_id_table_start;
|
||||
long long inode_table_start;
|
||||
long long directory_table_start;
|
||||
long long fragment_table_start;
|
||||
long long lookup_table_start;
|
||||
};
|
||||
|
||||
struct squashfs_dir_index {
|
||||
unsigned int index;
|
||||
unsigned int start_block;
|
||||
unsigned int size;
|
||||
unsigned char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_base_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_ipc_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
};
|
||||
|
||||
struct squashfs_lipc_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int xattr;
|
||||
};
|
||||
|
||||
struct squashfs_dev_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int rdev;
|
||||
};
|
||||
|
||||
struct squashfs_ldev_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int rdev;
|
||||
unsigned int xattr;
|
||||
};
|
||||
|
||||
struct squashfs_symlink_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int symlink_size;
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
struct squashfs_reg_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int start_block;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int file_size;
|
||||
unsigned int block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_lreg_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
squashfs_block start_block;
|
||||
long long file_size;
|
||||
long long sparse;
|
||||
unsigned int nlink;
|
||||
unsigned int fragment;
|
||||
unsigned int offset;
|
||||
unsigned int xattr;
|
||||
unsigned int block_list[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int start_block;
|
||||
unsigned int nlink;
|
||||
unsigned short file_size;
|
||||
unsigned short offset;
|
||||
unsigned int parent_inode;
|
||||
};
|
||||
|
||||
struct squashfs_ldir_inode_header {
|
||||
unsigned short inode_type;
|
||||
unsigned short mode;
|
||||
unsigned short uid;
|
||||
unsigned short guid;
|
||||
unsigned int mtime;
|
||||
unsigned int inode_number;
|
||||
unsigned int nlink;
|
||||
unsigned int file_size;
|
||||
unsigned int start_block;
|
||||
unsigned int parent_inode;
|
||||
unsigned short i_count;
|
||||
unsigned short offset;
|
||||
unsigned int xattr;
|
||||
struct squashfs_dir_index index[0];
|
||||
};
|
||||
|
||||
union squashfs_inode_header {
|
||||
struct squashfs_base_inode_header base;
|
||||
struct squashfs_dev_inode_header dev;
|
||||
struct squashfs_ldev_inode_header ldev;
|
||||
struct squashfs_symlink_inode_header symlink;
|
||||
struct squashfs_reg_inode_header reg;
|
||||
struct squashfs_lreg_inode_header lreg;
|
||||
struct squashfs_dir_inode_header dir;
|
||||
struct squashfs_ldir_inode_header ldir;
|
||||
struct squashfs_ipc_inode_header ipc;
|
||||
struct squashfs_lipc_inode_header lipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry {
|
||||
unsigned short offset;
|
||||
short inode_number;
|
||||
unsigned short type;
|
||||
unsigned short size;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
struct squashfs_dir_header {
|
||||
unsigned int count;
|
||||
unsigned int start_block;
|
||||
unsigned int inode_number;
|
||||
};
|
||||
|
||||
struct squashfs_fragment_entry {
|
||||
long long start_block;
|
||||
unsigned int size;
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_entry {
|
||||
unsigned short type;
|
||||
unsigned short size;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_val {
|
||||
unsigned int vsize;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_id {
|
||||
long long xattr;
|
||||
unsigned int count;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_table {
|
||||
long long xattr_table_start;
|
||||
unsigned int xattr_ids;
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
#endif
|
423
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_swap.h
Normal file
423
SQUASHFS/squashfs-tools-4.4/squashfs-tools/squashfs_swap.h
Normal file
|
@ -0,0 +1,423 @@
|
|||
#ifndef SQUASHFS_SWAP_H
|
||||
#define SQUASHFS_SWAP_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2008, 2009, 2010, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* squashfs_swap.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* macros to convert each stucture from big endian to little endian
|
||||
*/
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#include <stddef.h>
|
||||
extern void swap_le16(void *, void *);
|
||||
extern void swap_le32(void *, void *);
|
||||
extern void swap_le64(void *, void *);
|
||||
extern void swap_le16_num(void *, void *, int);
|
||||
extern void swap_le32_num(void *, void *, int);
|
||||
extern void swap_le64_num(void *, void *, int);
|
||||
extern unsigned short inswap_le16(unsigned short);
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
extern long long inswap_le64(long long);
|
||||
extern void inswap_le16_num(unsigned short *, int);
|
||||
extern void inswap_le32_num(unsigned int *, int);
|
||||
extern void inswap_le64_num(long long *, int);
|
||||
|
||||
#define _SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, s_magic, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, inodes, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, mkfs_time, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, block_size, struct squashfs_super_block);\
|
||||
SWAP_FUNC(32, s, d, fragments, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, compression, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, block_log, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, flags, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, no_ids, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, s_major, struct squashfs_super_block);\
|
||||
SWAP_FUNC(16, s, d, s_minor, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, root_inode, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, bytes_used, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, id_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, xattr_id_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, inode_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, directory_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, fragment_table_start, struct squashfs_super_block);\
|
||||
SWAP_FUNC(64, s, d, lookup_table_start, struct squashfs_super_block);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_INDEX(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, index, struct squashfs_dir_index);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_index);\
|
||||
SWAP_FUNC(32, s, d, size, struct squashfs_dir_index);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_base_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_base_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_IPC_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_ipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_ipc_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_lipc_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_lipc_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DEV_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_dev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, rdev, struct squashfs_dev_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, rdev, struct squashfs_ldev_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_ldev_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_symlink_inode_header);\
|
||||
SWAP_FUNC(32, s, d, symlink_size, struct squashfs_symlink_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_REG_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, fragment, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, offset, struct squashfs_reg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, file_size, struct squashfs_reg_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LREG_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(64, s, d, start_block, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(64, s, d, file_size, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(64, s, d, sparse, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, fragment, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, offset, struct squashfs_lreg_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_lreg_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, file_size, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, offset, struct squashfs_dir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, parent_inode, struct squashfs_dir_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, inode_type, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, mode, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, uid, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, guid, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, mtime, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, nlink, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, file_size, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, parent_inode, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, i_count, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(16, s, d, offset, struct squashfs_ldir_inode_header);\
|
||||
SWAP_FUNC(32, s, d, xattr, struct squashfs_ldir_inode_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_ENTRY(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, offset, struct squashfs_dir_entry);\
|
||||
SWAP_FUNC##S(16, s, d, inode_number, struct squashfs_dir_entry);\
|
||||
SWAP_FUNC(16, s, d, type, struct squashfs_dir_entry);\
|
||||
SWAP_FUNC(16, s, d, size, struct squashfs_dir_entry);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_DIR_HEADER(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, count, struct squashfs_dir_header);\
|
||||
SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_header);\
|
||||
SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_header);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(64, s, d, start_block, struct squashfs_fragment_entry);\
|
||||
SWAP_FUNC(32, s, d, size, struct squashfs_fragment_entry);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_ENTRY(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(16, s, d, type, struct squashfs_xattr_entry);\
|
||||
SWAP_FUNC(16, s, d, size, struct squashfs_xattr_entry);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_VAL(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(32, s, d, vsize, struct squashfs_xattr_val);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_ID(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(64, s, d, xattr, struct squashfs_xattr_id);\
|
||||
SWAP_FUNC(32, s, d, count, struct squashfs_xattr_id);\
|
||||
SWAP_FUNC(32, s, d, size, struct squashfs_xattr_id);\
|
||||
}
|
||||
|
||||
#define _SQUASHFS_SWAP_XATTR_TABLE(s, d, SWAP_FUNC) {\
|
||||
SWAP_FUNC(64, s, d, xattr_table_start, struct squashfs_xattr_table);\
|
||||
SWAP_FUNC(32, s, d, xattr_ids, struct squashfs_xattr_table);\
|
||||
}
|
||||
|
||||
/* big endian architecture copy and swap macros */
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
|
||||
_SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_INDEX(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_INDEX(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_IPC_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_DEV_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_REG_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LREG_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_ENTRY(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_DIR_HEADER(s, d) \
|
||||
_SQUASHFS_SWAP_DIR_HEADER(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \
|
||||
_SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_ENTRY(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_VAL(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_VAL(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_ID(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_ID(s, d, SWAP_LE)
|
||||
#define SQUASHFS_SWAP_XATTR_TABLE(s, d) \
|
||||
_SQUASHFS_SWAP_XATTR_TABLE(s, d, SWAP_LE)
|
||||
#define SWAP_LE(bits, s, d, field, type) \
|
||||
SWAP_LE##bits(((void *)(s)) + offsetof(type, field), \
|
||||
((void *)(d)) + offsetof(type, field))
|
||||
#define SWAP_LES(bits, s, d, field, type) \
|
||||
SWAP_LE(bits, s, d, field, type)
|
||||
#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \
|
||||
SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
|
||||
#define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n)
|
||||
#define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n)
|
||||
#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n)
|
||||
|
||||
#define SWAP_LE16(s, d) swap_le16(s, d)
|
||||
#define SWAP_LE32(s, d) swap_le32(s, d)
|
||||
#define SWAP_LE64(s, d) swap_le64(s, d)
|
||||
|
||||
/* big endian architecture swap in-place macros */
|
||||
#define SQUASHFS_INSWAP_SUPER_BLOCK(s) \
|
||||
_SQUASHFS_SWAP_SUPER_BLOCK(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_INDEX(s) \
|
||||
_SQUASHFS_SWAP_DIR_INDEX(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_BASE_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_BASE_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_IPC_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_IPC_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LIPC_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LIPC_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DEV_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_DEV_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LDEV_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LDEV_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_SYMLINK_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_REG_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_REG_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LREG_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LREG_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_DIR_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_LDIR_INODE_HEADER(s) \
|
||||
_SQUASHFS_SWAP_LDIR_INODE_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_ENTRY(s) \
|
||||
_SQUASHFS_SWAP_DIR_ENTRY(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_DIR_HEADER(s) \
|
||||
_SQUASHFS_SWAP_DIR_HEADER(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_ENTRY(s) \
|
||||
_SQUASHFS_SWAP_FRAGMENT_ENTRY(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_ENTRY(s) \
|
||||
_SQUASHFS_SWAP_XATTR_ENTRY(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_VAL(s) \
|
||||
_SQUASHFS_SWAP_XATTR_VAL(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_ID(s) \
|
||||
_SQUASHFS_SWAP_XATTR_ID(s, s, INSWAP_LE)
|
||||
#define SQUASHFS_INSWAP_XATTR_TABLE(s) \
|
||||
_SQUASHFS_SWAP_XATTR_TABLE(s, s, INSWAP_LE)
|
||||
#define INSWAP_LE(bits, s, d, field, type) \
|
||||
(s)->field = inswap_le##bits((s)->field)
|
||||
#define INSWAP_LES(bits, s, d, field, type) \
|
||||
(s)->field = (short) inswap_le##bits((unsigned short) \
|
||||
(s)->field)
|
||||
#define SQUASHFS_INSWAP_INODE_T(s) s = inswap_le64(s)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n) inswap_le64_num(s, n)
|
||||
#define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n) inswap_le64_num(s, n)
|
||||
#define SQUASHFS_INSWAP_ID_BLOCKS(s, n) inswap_le64_num(s, n)
|
||||
#define SQUASHFS_INSWAP_SHORTS(s, n) inswap_le16_num(s, n)
|
||||
#define SQUASHFS_INSWAP_INTS(s, n) inswap_le32_num(s, n)
|
||||
#define SQUASHFS_INSWAP_LONG_LONGS(s, n) inswap_le64_num(s, n)
|
||||
#else
|
||||
/* little endian architecture, just copy */
|
||||
#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_super_block))
|
||||
#define SQUASHFS_SWAP_DIR_INDEX(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_index))
|
||||
#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_base_inode_header))
|
||||
#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ipc_inode_header))
|
||||
#define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lipc_inode_header))
|
||||
#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dev_inode_header))
|
||||
#define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldev_inode_header))
|
||||
#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_symlink_inode_header))
|
||||
#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_reg_inode_header))
|
||||
#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lreg_inode_header))
|
||||
#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_inode_header))
|
||||
#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldir_inode_header))
|
||||
#define SQUASHFS_SWAP_DIR_ENTRY(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_entry))
|
||||
#define SQUASHFS_SWAP_DIR_HEADER(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_header))
|
||||
#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_fragment_entry))
|
||||
#define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_entry))
|
||||
#define SQUASHFS_SWAP_XATTR_VAL(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_val))
|
||||
#define SQUASHFS_SWAP_XATTR_ID(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_id))
|
||||
#define SQUASHFS_SWAP_XATTR_TABLE(s, d) \
|
||||
SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_table))
|
||||
#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
|
||||
#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \
|
||||
SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
#define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
|
||||
|
||||
#define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n)
|
||||
#define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short))
|
||||
#define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int))
|
||||
#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \
|
||||
memcpy(d, s, n * sizeof(long long))
|
||||
|
||||
/* little endian architecture, data already in place so do nothing */
|
||||
#define SQUASHFS_INSWAP_SUPER_BLOCK(s)
|
||||
#define SQUASHFS_INSWAP_DIR_INDEX(s)
|
||||
#define SQUASHFS_INSWAP_BASE_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_IPC_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LIPC_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_DEV_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LDEV_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_SYMLINK_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_REG_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LREG_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_DIR_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_LDIR_INODE_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_DIR_ENTRY(s)
|
||||
#define SQUASHFS_INSWAP_DIR_HEADER(s)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_ENTRY(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_ENTRY(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_VAL(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_ID(s)
|
||||
#define SQUASHFS_INSWAP_XATTR_TABLE(s)
|
||||
#define SQUASHFS_INSWAP_INODE_T(s)
|
||||
#define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n)
|
||||
#define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n)
|
||||
#define SQUASHFS_INSWAP_ID_BLOCKS(s, n)
|
||||
#define SQUASHFS_INSWAP_SHORTS(s, n)
|
||||
#define SQUASHFS_INSWAP_INTS(s, n)
|
||||
#define SQUASHFS_INSWAP_LONG_LONGS(s, n)
|
||||
#endif
|
||||
#endif
|
123
SQUASHFS/squashfs-tools-4.4/squashfs-tools/swap.c
Normal file
123
SQUASHFS/squashfs-tools-4.4/squashfs-tools/swap.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2010
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* swap.c
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
void swap_le16(void *src, void *dest)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
unsigned char *d = dest;
|
||||
|
||||
d[0] = s[1];
|
||||
d[1] = s[0];
|
||||
}
|
||||
|
||||
|
||||
void swap_le32(void *src, void *dest)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
unsigned char *d = dest;
|
||||
|
||||
d[0] = s[3];
|
||||
d[1] = s[2];
|
||||
d[2] = s[1];
|
||||
d[3] = s[0];
|
||||
}
|
||||
|
||||
|
||||
void swap_le64(void *src, void *dest)
|
||||
{
|
||||
unsigned char *s = src;
|
||||
unsigned char *d = dest;
|
||||
|
||||
d[0] = s[7];
|
||||
d[1] = s[6];
|
||||
d[2] = s[5];
|
||||
d[3] = s[4];
|
||||
d[4] = s[3];
|
||||
d[5] = s[2];
|
||||
d[6] = s[1];
|
||||
d[7] = s[0];
|
||||
}
|
||||
|
||||
|
||||
unsigned short inswap_le16(unsigned short num)
|
||||
{
|
||||
return (num >> 8) |
|
||||
((num & 0xff) << 8);
|
||||
}
|
||||
|
||||
|
||||
unsigned int inswap_le32(unsigned int num)
|
||||
{
|
||||
return (num >> 24) |
|
||||
((num & 0xff0000) >> 8) |
|
||||
((num & 0xff00) << 8) |
|
||||
((num & 0xff) << 24);
|
||||
}
|
||||
|
||||
|
||||
long long inswap_le64(long long n)
|
||||
{
|
||||
unsigned long long num = n;
|
||||
|
||||
return (num >> 56) |
|
||||
((num & 0xff000000000000LL) >> 40) |
|
||||
((num & 0xff0000000000LL) >> 24) |
|
||||
((num & 0xff00000000LL) >> 8) |
|
||||
((num & 0xff000000) << 8) |
|
||||
((num & 0xff0000) << 24) |
|
||||
((num & 0xff00) << 40) |
|
||||
((num & 0xff) << 56);
|
||||
}
|
||||
|
||||
|
||||
#define SWAP_LE_NUM(BITS) \
|
||||
void swap_le##BITS##_num(void *s, void *d, int n) \
|
||||
{\
|
||||
int i;\
|
||||
for(i = 0; i < n; i++, s += BITS / 8, d += BITS / 8)\
|
||||
swap_le##BITS(s, d);\
|
||||
}
|
||||
|
||||
SWAP_LE_NUM(16)
|
||||
SWAP_LE_NUM(32)
|
||||
SWAP_LE_NUM(64)
|
||||
|
||||
#define INSWAP_LE_NUM(BITS, TYPE) \
|
||||
void inswap_le##BITS##_num(TYPE *s, int n) \
|
||||
{\
|
||||
int i;\
|
||||
for(i = 0; i < n; i++)\
|
||||
s[i] = inswap_le##BITS(s[i]);\
|
||||
}
|
||||
|
||||
INSWAP_LE_NUM(16, unsigned short)
|
||||
INSWAP_LE_NUM(32, unsigned int)
|
||||
INSWAP_LE_NUM(64, long long)
|
||||
#endif
|
411
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-1.c
Normal file
411
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-1.c
Normal file
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-1.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
static unsigned int *uid_table, *guid_table;
|
||||
static char *inode_table, *directory_table;
|
||||
static squashfs_operations ops;
|
||||
|
||||
static void read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
|
||||
{
|
||||
unsigned short block_size;
|
||||
int i;
|
||||
|
||||
TRACE("read_block_list: blocks %d\n", blocks);
|
||||
|
||||
for(i = 0; i < blocks; i++, block_ptr += 2) {
|
||||
if(swap) {
|
||||
unsigned short sblock_size;
|
||||
memcpy(&sblock_size, block_ptr, sizeof(unsigned short));
|
||||
SQUASHFS_SWAP_SHORTS_3((&block_size), &sblock_size, 1);
|
||||
} else
|
||||
memcpy(&block_size, block_ptr, sizeof(unsigned short));
|
||||
block_list[i] = SQUASHFS_COMPRESSED_SIZE(block_size) |
|
||||
(SQUASHFS_COMPRESSED(block_size) ? 0 :
|
||||
SQUASHFS_COMPRESSED_BIT_BLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct inode *read_inode(unsigned int start_block, unsigned int offset)
|
||||
{
|
||||
static union squashfs_inode_header_1 header;
|
||||
long long start = sBlk.s.inode_table_start + start_block;
|
||||
int bytes = lookup_entry(inode_table_hash, start);
|
||||
char *block_ptr = inode_table + bytes + offset;
|
||||
static struct inode i;
|
||||
|
||||
TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
|
||||
start);
|
||||
|
||||
if(swap) {
|
||||
squashfs_base_inode_header_1 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.base));
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_1(&header.base, &sinode,
|
||||
sizeof(squashfs_base_inode_header_1));
|
||||
} else
|
||||
memcpy(&header.base, block_ptr, sizeof(header.base));
|
||||
|
||||
i.uid = (uid_t) uid_table[(header.base.inode_type - 1) /
|
||||
SQUASHFS_TYPES * 16 + header.base.uid];
|
||||
if(header.base.inode_type == SQUASHFS_IPC_TYPE) {
|
||||
squashfs_ipc_inode_header_1 *inodep = &header.ipc;
|
||||
|
||||
if(swap) {
|
||||
squashfs_ipc_inode_header_1 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_IPC_INODE_HEADER_1(inodep, &sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
if(inodep->type == SQUASHFS_SOCKET_TYPE) {
|
||||
i.mode = S_IFSOCK | header.base.mode;
|
||||
i.type = SQUASHFS_SOCKET_TYPE;
|
||||
} else {
|
||||
i.mode = S_IFIFO | header.base.mode;
|
||||
i.type = SQUASHFS_FIFO_TYPE;
|
||||
}
|
||||
i.uid = (uid_t) uid_table[inodep->offset * 16 + inodep->uid];
|
||||
} else {
|
||||
i.mode = lookup_type[(header.base.inode_type - 1) %
|
||||
SQUASHFS_TYPES + 1] | header.base.mode;
|
||||
i.type = (header.base.inode_type - 1) % SQUASHFS_TYPES + 1;
|
||||
}
|
||||
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
i.gid = header.base.guid == 15 ? i.uid :
|
||||
(uid_t) guid_table[header.base.guid];
|
||||
i.time = sBlk.s.mkfs_time;
|
||||
i.inode_number = inode_number ++;
|
||||
|
||||
switch(i.type) {
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
squashfs_dir_inode_header_1 *inode = &header.dir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dir_inode_header_1 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.dir));
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER_1(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(header.dir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.time = inode->mtime;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
squashfs_reg_inode_header_1 *inode = &header.reg;
|
||||
|
||||
if(swap) {
|
||||
squashfs_reg_inode_header_1 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(sinode));
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER_1(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(*inode));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.time = inode->mtime;
|
||||
i.blocks = (i.data + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
i.fragment = 0;
|
||||
i.frag_bytes = 0;
|
||||
i.offset = 0;
|
||||
i.sparse = 0;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE: {
|
||||
squashfs_symlink_inode_header_1 *inodep =
|
||||
&header.symlink;
|
||||
|
||||
if(swap) {
|
||||
squashfs_symlink_inode_header_1 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.symlink = malloc(inodep->symlink_size + 1);
|
||||
if(i.symlink == NULL)
|
||||
EXIT_UNSQUASH("read_inode: failed to malloc "
|
||||
"symlink data\n");
|
||||
strncpy(i.symlink, block_ptr +
|
||||
sizeof(squashfs_symlink_inode_header_1),
|
||||
inodep->symlink_size);
|
||||
i.symlink[inodep->symlink_size] = '\0';
|
||||
i.data = inodep->symlink_size;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
squashfs_dev_inode_header_1 *inodep = &header.dev;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dev_inode_header_1 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER_1(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.data = inodep->rdev;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE: {
|
||||
i.data = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
EXIT_UNSQUASH("Unknown inode type %d in "
|
||||
" read_inode_header_1!\n",
|
||||
header.base.inode_type);
|
||||
}
|
||||
return &i;
|
||||
}
|
||||
|
||||
|
||||
static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset,
|
||||
struct inode **i)
|
||||
{
|
||||
squashfs_dir_header_2 dirh;
|
||||
char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__((aligned));
|
||||
squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
|
||||
long long start;
|
||||
int bytes;
|
||||
int dir_count, size;
|
||||
struct dir_ent *new_dir;
|
||||
struct dir *dir;
|
||||
|
||||
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
|
||||
block_start, offset);
|
||||
|
||||
*i = read_inode(block_start, offset);
|
||||
|
||||
dir = malloc(sizeof(struct dir));
|
||||
if(dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
|
||||
|
||||
dir->dir_count = 0;
|
||||
dir->cur_entry = 0;
|
||||
dir->mode = (*i)->mode;
|
||||
dir->uid = (*i)->uid;
|
||||
dir->guid = (*i)->gid;
|
||||
dir->mtime = (*i)->time;
|
||||
dir->xattr = (*i)->xattr;
|
||||
dir->dirs = NULL;
|
||||
|
||||
if ((*i)->data == 0)
|
||||
/*
|
||||
* if the directory is empty, skip the unnecessary
|
||||
* lookup_entry, this fixes the corner case with
|
||||
* completely empty filesystems where lookup_entry correctly
|
||||
* returning -1 is incorrectly treated as an error
|
||||
*/
|
||||
return dir;
|
||||
|
||||
start = sBlk.s.directory_table_start + (*i)->start;
|
||||
bytes = lookup_entry(directory_table_hash, start);
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
|
||||
"found!\n", block_start);
|
||||
|
||||
bytes += (*i)->offset;
|
||||
size = (*i)->data + bytes;
|
||||
|
||||
while(bytes < size) {
|
||||
if(swap) {
|
||||
squashfs_dir_header_2 sdirh;
|
||||
memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
|
||||
SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
|
||||
} else
|
||||
memcpy(&dirh, directory_table + bytes, sizeof(dirh));
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
TRACE("squashfs_opendir: Read directory header @ byte position "
|
||||
"%d, %d directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
while(dir_count--) {
|
||||
if(swap) {
|
||||
squashfs_dir_entry_2 sdire;
|
||||
memcpy(&sdire, directory_table + bytes,
|
||||
sizeof(sdire));
|
||||
SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
|
||||
} else
|
||||
memcpy(dire, directory_table + bytes,
|
||||
sizeof(*dire));
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_opendir: directory entry %s, inode "
|
||||
"%d:%d, type %d\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
if((dir->dir_count % DIR_ENT_SIZE) == 0) {
|
||||
new_dir = realloc(dir->dirs, (dir->dir_count +
|
||||
DIR_ENT_SIZE) * sizeof(struct dir_ent));
|
||||
if(new_dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: "
|
||||
"realloc failed!\n");
|
||||
dir->dirs = new_dir;
|
||||
}
|
||||
strcpy(dir->dirs[dir->dir_count].name, dire->name);
|
||||
dir->dirs[dir->dir_count].start_block =
|
||||
dirh.start_block;
|
||||
dir->dirs[dir->dir_count].offset = dire->offset;
|
||||
dir->dirs[dir->dir_count].type = dire->type;
|
||||
dir->dir_count ++;
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
||||
corrupted:
|
||||
free(dir->dirs);
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
squashfs_operations *read_filesystem_tables_1()
|
||||
{
|
||||
long long table_start;
|
||||
|
||||
/* Read uid and gid lookup tables */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.no_guids) {
|
||||
if(sBlk.guid_start >= sBlk.s.bytes_used) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* In 1.x filesystems, there should never be more than 15 gids */
|
||||
if(sBlk.no_guids > 15) {
|
||||
ERROR("read_filesystem_tables: gids too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_guids, sBlk.guid_start, sBlk.s.bytes_used, &guid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.guid_start;
|
||||
} else {
|
||||
/* no guids, guid_start should be 0 */
|
||||
if(sBlk.guid_start != 0) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
table_start = sBlk.s.bytes_used;
|
||||
}
|
||||
|
||||
if(sBlk.uid_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: uid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* There should be at least one uid */
|
||||
if(sBlk.no_uids == 0) {
|
||||
ERROR("read_filesystem_tables: uid count bad in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* In 1.x filesystems, there should never be more than 48 uids */
|
||||
if(sBlk.no_uids > 48) {
|
||||
ERROR("read_filesystem_tables: uids too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_uids, sBlk.uid_start, table_start, &uid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.uid_start;
|
||||
|
||||
/* Read directory table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.directory_table_start > table_start) {
|
||||
ERROR("read_filesystem_tables: directory table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
directory_table = read_directory_table(sBlk.s.directory_table_start,
|
||||
table_start);
|
||||
if(directory_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
/* Read inode table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
|
||||
ERROR("read_filesystem_tables: inode table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
inode_table = read_inode_table(sBlk.s.inode_table_start,
|
||||
sBlk.s.directory_table_start);
|
||||
if(inode_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
return &ops;
|
||||
|
||||
corrupted:
|
||||
ERROR("File system corruption detected\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static squashfs_operations ops = {
|
||||
.opendir = squashfs_opendir,
|
||||
.read_block_list = read_block_list,
|
||||
.read_inode = read_inode
|
||||
};
|
83
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-123.c
Normal file
83
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-123.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-123.c
|
||||
*
|
||||
* Helper functions used by unsquash-1, unsquash-2 and unsquash-3.
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
int read_ids(int ids, long long start, long long end, unsigned int **id_table)
|
||||
{
|
||||
/* Note on overflow limits:
|
||||
* Size of ids is 2^8
|
||||
* Max length is 2^8*4 or 1024
|
||||
*/
|
||||
int res;
|
||||
int length = ids * sizeof(unsigned int);
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (end - start)) {
|
||||
ERROR("read_ids: Bad inode count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_ids: no_ids %d\n", ids);
|
||||
|
||||
*id_table = malloc(length);
|
||||
if(*id_table == NULL) {
|
||||
ERROR("read_ids: failed to allocate uid/gid table\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(swap) {
|
||||
unsigned int *sid_table = malloc(length);
|
||||
|
||||
if(sid_table == NULL) {
|
||||
ERROR("read_ids: failed to allocate uid/gid table\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = read_fs_bytes(fd, start, length, sid_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_ids: failed to read uid/gid table"
|
||||
"\n");
|
||||
free(sid_table);
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_SWAP_INTS_3((*id_table), sid_table, ids);
|
||||
free(sid_table);
|
||||
} else {
|
||||
res = read_fs_bytes(fd, start, length, *id_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_ids: failed to read uid/gid table"
|
||||
"\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
529
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-2.c
Normal file
529
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-2.c
Normal file
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-2.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
static squashfs_fragment_entry_2 *fragment_table;
|
||||
static unsigned int *uid_table, *guid_table;
|
||||
static char *inode_table, *directory_table;
|
||||
static squashfs_operations ops;
|
||||
|
||||
static void read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
|
||||
{
|
||||
TRACE("read_block_list: blocks %d\n", blocks);
|
||||
|
||||
if(swap) {
|
||||
SQUASHFS_SWAP_INTS_3(block_list, block_ptr, blocks);
|
||||
} else
|
||||
memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
|
||||
static int read_fragment_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.fragments is 2^32 (unsigned int)
|
||||
* Max size of bytes is 2^32*8 or 2^35
|
||||
* Max indexes is (2^32*8)/8K or 2^22
|
||||
* Max length is ((2^32*8)/8K)*4 or 2^24 or 16M
|
||||
*/
|
||||
int res, i;
|
||||
long long bytes = SQUASHFS_FRAGMENT_BYTES_2((long long) sBlk.s.fragments);
|
||||
int indexes = SQUASHFS_FRAGMENT_INDEXES_2((long long) sBlk.s.fragments);
|
||||
int length = SQUASHFS_FRAGMENT_INDEX_BYTES_2((long long) sBlk.s.fragments);
|
||||
unsigned int *fragment_table_index;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start- sBlk.s.fragment_table_start)) {
|
||||
ERROR("read_ids: Bad inode count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
|
||||
"from 0x%llx\n", sBlk.s.fragments, indexes,
|
||||
sBlk.s.fragment_table_start);
|
||||
|
||||
fragment_table_index = malloc(length);
|
||||
if(fragment_table_index == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table index\n");
|
||||
|
||||
fragment_table = malloc(bytes);
|
||||
if(fragment_table == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table\n");
|
||||
|
||||
if(swap) {
|
||||
unsigned int *sfragment_table_index = malloc(length);
|
||||
|
||||
if(sfragment_table_index == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table index\n");
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start,
|
||||
length, sfragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
free(sfragment_table_index);
|
||||
goto failed;
|
||||
}
|
||||
SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index,
|
||||
sfragment_table_index, indexes);
|
||||
free(sfragment_table_index);
|
||||
} else {
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start,
|
||||
length, fragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, fragment_table_index[i], NULL,
|
||||
expected, ((char *) fragment_table) + ((long long) i *
|
||||
SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read fragment table block %d, from 0x%x, length %d\n", i,
|
||||
fragment_table_index[i], length);
|
||||
if(length == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table block\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if(swap) {
|
||||
squashfs_fragment_entry_2 sfragment;
|
||||
for(i = 0; i < sBlk.s.fragments; i++) {
|
||||
SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment),
|
||||
(&fragment_table[i]));
|
||||
memcpy((char *) &fragment_table[i], (char *) &sfragment,
|
||||
sizeof(squashfs_fragment_entry_2));
|
||||
}
|
||||
}
|
||||
|
||||
*table_start = fragment_table_index[0];
|
||||
free(fragment_table_index);
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
free(fragment_table_index);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void read_fragment(unsigned int fragment, long long *start_block, int *size)
|
||||
{
|
||||
TRACE("read_fragment: reading fragment %d\n", fragment);
|
||||
|
||||
squashfs_fragment_entry_2 *fragment_entry = &fragment_table[fragment];
|
||||
*start_block = fragment_entry->start_block;
|
||||
*size = fragment_entry->size;
|
||||
}
|
||||
|
||||
|
||||
static struct inode *read_inode(unsigned int start_block, unsigned int offset)
|
||||
{
|
||||
static union squashfs_inode_header_2 header;
|
||||
long long start = sBlk.s.inode_table_start + start_block;
|
||||
int bytes = lookup_entry(inode_table_hash, start);
|
||||
char *block_ptr = inode_table + bytes + offset;
|
||||
static struct inode i;
|
||||
|
||||
TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
|
||||
start);
|
||||
|
||||
if(swap) {
|
||||
squashfs_base_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.base));
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode,
|
||||
sizeof(squashfs_base_inode_header_2));
|
||||
} else
|
||||
memcpy(&header.base, block_ptr, sizeof(header.base));
|
||||
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
i.uid = (uid_t) uid_table[header.base.uid];
|
||||
i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid :
|
||||
(uid_t) guid_table[header.base.guid];
|
||||
i.mode = lookup_type[header.base.inode_type] | header.base.mode;
|
||||
i.type = header.base.inode_type;
|
||||
i.time = sBlk.s.mkfs_time;
|
||||
i.inode_number = inode_number++;
|
||||
|
||||
switch(header.base.inode_type) {
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
squashfs_dir_inode_header_2 *inode = &header.dir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dir_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.dir));
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(&header.dir, block_ptr,
|
||||
sizeof(header.dir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.time = inode->mtime;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
squashfs_ldir_inode_header_2 *inode = &header.ldir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_ldir_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.ldir));
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(&header.ldir, block_ptr,
|
||||
sizeof(header.ldir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.time = inode->mtime;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
squashfs_reg_inode_header_2 *inode = &header.reg;
|
||||
|
||||
if(swap) {
|
||||
squashfs_reg_inode_header_2 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(sinode));
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER_2(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(*inode));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.time = inode->mtime;
|
||||
i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
|
||||
? 0 : inode->file_size % sBlk.s.block_size;
|
||||
i.fragment = inode->fragment;
|
||||
i.offset = inode->offset;
|
||||
i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(i.data + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log : i.data >>
|
||||
sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.sparse = 0;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE: {
|
||||
squashfs_symlink_inode_header_2 *inodep =
|
||||
&header.symlink;
|
||||
|
||||
if(swap) {
|
||||
squashfs_symlink_inode_header_2 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.symlink = malloc(inodep->symlink_size + 1);
|
||||
if(i.symlink == NULL)
|
||||
EXIT_UNSQUASH("read_inode: failed to malloc "
|
||||
"symlink data\n");
|
||||
strncpy(i.symlink, block_ptr +
|
||||
sizeof(squashfs_symlink_inode_header_2),
|
||||
inodep->symlink_size);
|
||||
i.symlink[inodep->symlink_size] = '\0';
|
||||
i.data = inodep->symlink_size;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
squashfs_dev_inode_header_2 *inodep = &header.dev;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dev_inode_header_2 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.data = inodep->rdev;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
i.data = 0;
|
||||
break;
|
||||
default:
|
||||
EXIT_UNSQUASH("Unknown inode type %d in "
|
||||
"read_inode_header_2!\n",
|
||||
header.base.inode_type);
|
||||
}
|
||||
return &i;
|
||||
}
|
||||
|
||||
|
||||
static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset,
|
||||
struct inode **i)
|
||||
{
|
||||
squashfs_dir_header_2 dirh;
|
||||
char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__((aligned));
|
||||
squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
|
||||
long long start;
|
||||
int bytes;
|
||||
int dir_count, size;
|
||||
struct dir_ent *new_dir;
|
||||
struct dir *dir;
|
||||
|
||||
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
|
||||
block_start, offset);
|
||||
|
||||
*i = read_inode(block_start, offset);
|
||||
|
||||
dir = malloc(sizeof(struct dir));
|
||||
if(dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
|
||||
|
||||
dir->dir_count = 0;
|
||||
dir->cur_entry = 0;
|
||||
dir->mode = (*i)->mode;
|
||||
dir->uid = (*i)->uid;
|
||||
dir->guid = (*i)->gid;
|
||||
dir->mtime = (*i)->time;
|
||||
dir->xattr = (*i)->xattr;
|
||||
dir->dirs = NULL;
|
||||
|
||||
if ((*i)->data == 0)
|
||||
/*
|
||||
* if the directory is empty, skip the unnecessary
|
||||
* lookup_entry, this fixes the corner case with
|
||||
* completely empty filesystems where lookup_entry correctly
|
||||
* returning -1 is incorrectly treated as an error
|
||||
*/
|
||||
return dir;
|
||||
|
||||
start = sBlk.s.directory_table_start + (*i)->start;
|
||||
bytes = lookup_entry(directory_table_hash, start);
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
|
||||
"found!\n", block_start);
|
||||
|
||||
bytes += (*i)->offset;
|
||||
size = (*i)->data + bytes;
|
||||
|
||||
while(bytes < size) {
|
||||
if(swap) {
|
||||
squashfs_dir_header_2 sdirh;
|
||||
memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
|
||||
SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
|
||||
} else
|
||||
memcpy(&dirh, directory_table + bytes, sizeof(dirh));
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
TRACE("squashfs_opendir: Read directory header @ byte position "
|
||||
"%d, %d directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
while(dir_count--) {
|
||||
if(swap) {
|
||||
squashfs_dir_entry_2 sdire;
|
||||
memcpy(&sdire, directory_table + bytes,
|
||||
sizeof(sdire));
|
||||
SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
|
||||
} else
|
||||
memcpy(dire, directory_table + bytes,
|
||||
sizeof(*dire));
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_opendir: directory entry %s, inode "
|
||||
"%d:%d, type %d\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
if((dir->dir_count % DIR_ENT_SIZE) == 0) {
|
||||
new_dir = realloc(dir->dirs, (dir->dir_count +
|
||||
DIR_ENT_SIZE) * sizeof(struct dir_ent));
|
||||
if(new_dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: "
|
||||
"realloc failed!\n");
|
||||
dir->dirs = new_dir;
|
||||
}
|
||||
strcpy(dir->dirs[dir->dir_count].name, dire->name);
|
||||
dir->dirs[dir->dir_count].start_block =
|
||||
dirh.start_block;
|
||||
dir->dirs[dir->dir_count].offset = dire->offset;
|
||||
dir->dirs[dir->dir_count].type = dire->type;
|
||||
dir->dir_count ++;
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
||||
corrupted:
|
||||
free(dir->dirs);
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
squashfs_operations *read_filesystem_tables_2()
|
||||
{
|
||||
long long table_start;
|
||||
|
||||
/* Read uid and gid lookup tables */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.no_guids) {
|
||||
if(sBlk.guid_start >= sBlk.s.bytes_used) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_guids, sBlk.guid_start, sBlk.s.bytes_used, &guid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.guid_start;
|
||||
} else {
|
||||
/* no guids, guid_start should be 0 */
|
||||
if(sBlk.guid_start != 0) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
table_start = sBlk.s.bytes_used;
|
||||
}
|
||||
|
||||
if(sBlk.uid_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: uid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* There should be at least one uid */
|
||||
if(sBlk.no_uids == 0) {
|
||||
ERROR("read_filesystem_tables: uid count bad in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_uids, sBlk.uid_start, table_start, &uid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.uid_start;
|
||||
|
||||
/* Read fragment table */
|
||||
if(sBlk.s.fragments != 0) {
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.fragment_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* The number of fragments should not exceed the number of inodes */
|
||||
if(sBlk.s.fragments > sBlk.s.inodes) {
|
||||
ERROR("read_filesystem_tables: Bad fragment count in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_fragment_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
} else {
|
||||
/*
|
||||
* Sanity check super block contents - with 0 fragments,
|
||||
* the fragment table should be empty
|
||||
*/
|
||||
if(sBlk.s.fragment_table_start != table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start invalid in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read directory table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.directory_table_start > table_start) {
|
||||
ERROR("read_filesystem_tables: directory table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
directory_table = read_directory_table(sBlk.s.directory_table_start,
|
||||
table_start);
|
||||
if(directory_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
/* Read inode table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
|
||||
ERROR("read_filesystem_tables: inode table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
inode_table = read_inode_table(sBlk.s.inode_table_start,
|
||||
sBlk.s.directory_table_start);
|
||||
if(inode_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
return &ops;
|
||||
|
||||
corrupted:
|
||||
ERROR("File system corruption detected\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static squashfs_operations ops = {
|
||||
.opendir = squashfs_opendir,
|
||||
.read_fragment = read_fragment,
|
||||
.read_block_list = read_block_list,
|
||||
.read_inode = read_inode
|
||||
};
|
632
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-3.c
Normal file
632
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-3.c
Normal file
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-3.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_compat.h"
|
||||
|
||||
static squashfs_fragment_entry_3 *fragment_table;
|
||||
static unsigned int *uid_table, *guid_table;
|
||||
static char *inode_table, *directory_table;
|
||||
static squashfs_operations ops;
|
||||
|
||||
static long long *salloc_index_table(int indexes)
|
||||
{
|
||||
static long long *alloc_table = NULL;
|
||||
static int alloc_size = 0;
|
||||
int length = indexes * sizeof(long long);
|
||||
|
||||
if(alloc_size < length || length == 0) {
|
||||
long long *table = realloc(alloc_table, length);
|
||||
|
||||
if(table == NULL && length !=0 )
|
||||
EXIT_UNSQUASH("alloc_index_table: failed to allocate "
|
||||
"index table\n");
|
||||
|
||||
alloc_table = table;
|
||||
alloc_size = length;
|
||||
}
|
||||
|
||||
return alloc_table;
|
||||
}
|
||||
|
||||
|
||||
static void read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
|
||||
{
|
||||
TRACE("read_block_list: blocks %d\n", blocks);
|
||||
|
||||
if(swap) {
|
||||
SQUASHFS_SWAP_INTS_3(block_list, block_ptr, blocks);
|
||||
} else
|
||||
memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
|
||||
static int read_fragment_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.fragments is 2^32 (unsigned int)
|
||||
* Max size of bytes is 2^32*16 or 2^36
|
||||
* Max indexes is (2^32*16)/8K or 2^23
|
||||
* Max length is ((2^32*16)/8K)*8 or 2^26 or 64M
|
||||
*/
|
||||
int res, i;
|
||||
long long bytes = SQUASHFS_FRAGMENT_BYTES_3((long long) sBlk.s.fragments);
|
||||
int indexes = SQUASHFS_FRAGMENT_INDEXES_3((long long) sBlk.s.fragments);
|
||||
int length = SQUASHFS_FRAGMENT_INDEX_BYTES_3((long long) sBlk.s.fragments);
|
||||
long long *fragment_table_index;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start - sBlk.s.fragment_table_start)) {
|
||||
ERROR("read_fragment_table: Bad fragment count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
|
||||
"from 0x%llx\n", sBlk.s.fragments, indexes,
|
||||
sBlk.s.fragment_table_start);
|
||||
|
||||
fragment_table_index = alloc_index_table(indexes);
|
||||
fragment_table = malloc(bytes);
|
||||
if(fragment_table == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table\n");
|
||||
|
||||
if(swap) {
|
||||
long long *sfragment_table_index = salloc_index_table(indexes);
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start,
|
||||
length, sfragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_SWAP_FRAGMENT_INDEXES_3(fragment_table_index,
|
||||
sfragment_table_index, indexes);
|
||||
} else {
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start,
|
||||
length, fragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, fragment_table_index[i], NULL,
|
||||
expected, ((char *) fragment_table) + ((long long) i *
|
||||
SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
|
||||
i, fragment_table_index[i], length);
|
||||
if(length == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table block\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(swap) {
|
||||
squashfs_fragment_entry_3 sfragment;
|
||||
for(i = 0; i < sBlk.s.fragments; i++) {
|
||||
SQUASHFS_SWAP_FRAGMENT_ENTRY_3((&sfragment),
|
||||
(&fragment_table[i]));
|
||||
memcpy((char *) &fragment_table[i], (char *) &sfragment,
|
||||
sizeof(squashfs_fragment_entry_3));
|
||||
}
|
||||
}
|
||||
|
||||
*table_start = fragment_table_index[0];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void read_fragment(unsigned int fragment, long long *start_block, int *size)
|
||||
{
|
||||
TRACE("read_fragment: reading fragment %d\n", fragment);
|
||||
|
||||
squashfs_fragment_entry_3 *fragment_entry = &fragment_table[fragment];
|
||||
*start_block = fragment_entry->start_block;
|
||||
*size = fragment_entry->size;
|
||||
}
|
||||
|
||||
|
||||
static struct inode *read_inode(unsigned int start_block, unsigned int offset)
|
||||
{
|
||||
static union squashfs_inode_header_3 header;
|
||||
long long start = sBlk.s.inode_table_start + start_block;
|
||||
int bytes = lookup_entry(inode_table_hash, start);
|
||||
char *block_ptr = inode_table + bytes + offset;
|
||||
static struct inode i;
|
||||
|
||||
TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
|
||||
start);
|
||||
|
||||
if(swap) {
|
||||
squashfs_base_inode_header_3 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.base));
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER_3(&header.base, &sinode,
|
||||
sizeof(squashfs_base_inode_header_3));
|
||||
} else
|
||||
memcpy(&header.base, block_ptr, sizeof(header.base));
|
||||
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
i.uid = (uid_t) uid_table[header.base.uid];
|
||||
i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid :
|
||||
(uid_t) guid_table[header.base.guid];
|
||||
i.mode = lookup_type[header.base.inode_type] | header.base.mode;
|
||||
i.type = header.base.inode_type;
|
||||
i.time = header.base.mtime;
|
||||
i.inode_number = header.base.inode_number;
|
||||
|
||||
switch(header.base.inode_type) {
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
squashfs_dir_inode_header_3 *inode = &header.dir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dir_inode_header_3 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.dir));
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER_3(&header.dir,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(&header.dir, block_ptr,
|
||||
sizeof(header.dir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
squashfs_ldir_inode_header_3 *inode = &header.ldir;
|
||||
|
||||
if(swap) {
|
||||
squashfs_ldir_inode_header_3 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(header.ldir));
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER_3(&header.ldir,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(&header.ldir, block_ptr,
|
||||
sizeof(header.ldir));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
squashfs_reg_inode_header_3 *inode = &header.reg;
|
||||
|
||||
if(swap) {
|
||||
squashfs_reg_inode_header_3 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(sinode));
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER_3(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(*inode));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
|
||||
? 0 : inode->file_size % sBlk.s.block_size;
|
||||
i.fragment = inode->fragment;
|
||||
i.offset = inode->offset;
|
||||
i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(i.data + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log :
|
||||
i.data >> sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.sparse = 1;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LREG_TYPE: {
|
||||
squashfs_lreg_inode_header_3 *inode = &header.lreg;
|
||||
|
||||
if(swap) {
|
||||
squashfs_lreg_inode_header_3 sinode;
|
||||
memcpy(&sinode, block_ptr, sizeof(sinode));
|
||||
SQUASHFS_SWAP_LREG_INODE_HEADER_3(inode,
|
||||
&sinode);
|
||||
} else
|
||||
memcpy(inode, block_ptr, sizeof(*inode));
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
|
||||
? 0 : inode->file_size % sBlk.s.block_size;
|
||||
i.fragment = inode->fragment;
|
||||
i.offset = inode->offset;
|
||||
i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(inode->file_size + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log :
|
||||
inode->file_size >> sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.sparse = 1;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE: {
|
||||
squashfs_symlink_inode_header_3 *inodep =
|
||||
&header.symlink;
|
||||
|
||||
if(swap) {
|
||||
squashfs_symlink_inode_header_3 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER_3(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.symlink = malloc(inodep->symlink_size + 1);
|
||||
if(i.symlink == NULL)
|
||||
EXIT_UNSQUASH("read_inode: failed to malloc "
|
||||
"symlink data\n");
|
||||
strncpy(i.symlink, block_ptr +
|
||||
sizeof(squashfs_symlink_inode_header_3),
|
||||
inodep->symlink_size);
|
||||
i.symlink[inodep->symlink_size] = '\0';
|
||||
i.data = inodep->symlink_size;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
squashfs_dev_inode_header_3 *inodep = &header.dev;
|
||||
|
||||
if(swap) {
|
||||
squashfs_dev_inode_header_3 sinodep;
|
||||
memcpy(&sinodep, block_ptr, sizeof(sinodep));
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER_3(inodep,
|
||||
&sinodep);
|
||||
} else
|
||||
memcpy(inodep, block_ptr, sizeof(*inodep));
|
||||
|
||||
i.data = inodep->rdev;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
i.data = 0;
|
||||
break;
|
||||
default:
|
||||
EXIT_UNSQUASH("Unknown inode type %d in read_inode!\n",
|
||||
header.base.inode_type);
|
||||
}
|
||||
return &i;
|
||||
}
|
||||
|
||||
|
||||
static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset,
|
||||
struct inode **i)
|
||||
{
|
||||
squashfs_dir_header_3 dirh;
|
||||
char buffer[sizeof(squashfs_dir_entry_3) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__((aligned));
|
||||
squashfs_dir_entry_3 *dire = (squashfs_dir_entry_3 *) buffer;
|
||||
long long start;
|
||||
int bytes;
|
||||
int dir_count, size;
|
||||
struct dir_ent *new_dir;
|
||||
struct dir *dir;
|
||||
|
||||
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
|
||||
block_start, offset);
|
||||
|
||||
*i = read_inode(block_start, offset);
|
||||
|
||||
dir = malloc(sizeof(struct dir));
|
||||
if(dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
|
||||
|
||||
dir->dir_count = 0;
|
||||
dir->cur_entry = 0;
|
||||
dir->mode = (*i)->mode;
|
||||
dir->uid = (*i)->uid;
|
||||
dir->guid = (*i)->gid;
|
||||
dir->mtime = (*i)->time;
|
||||
dir->xattr = (*i)->xattr;
|
||||
dir->dirs = NULL;
|
||||
|
||||
if ((*i)->data == 3)
|
||||
/*
|
||||
* if the directory is empty, skip the unnecessary
|
||||
* lookup_entry, this fixes the corner case with
|
||||
* completely empty filesystems where lookup_entry correctly
|
||||
* returning -1 is incorrectly treated as an error
|
||||
*/
|
||||
return dir;
|
||||
|
||||
start = sBlk.s.directory_table_start + (*i)->start;
|
||||
bytes = lookup_entry(directory_table_hash, start);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
|
||||
"found!\n", block_start);
|
||||
|
||||
bytes += (*i)->offset;
|
||||
size = (*i)->data + bytes - 3;
|
||||
|
||||
while(bytes < size) {
|
||||
if(swap) {
|
||||
squashfs_dir_header_3 sdirh;
|
||||
memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
|
||||
SQUASHFS_SWAP_DIR_HEADER_3(&dirh, &sdirh);
|
||||
} else
|
||||
memcpy(&dirh, directory_table + bytes, sizeof(dirh));
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
TRACE("squashfs_opendir: Read directory header @ byte position "
|
||||
"%d, %d directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
while(dir_count--) {
|
||||
if(swap) {
|
||||
squashfs_dir_entry_3 sdire;
|
||||
memcpy(&sdire, directory_table + bytes,
|
||||
sizeof(sdire));
|
||||
SQUASHFS_SWAP_DIR_ENTRY_3(dire, &sdire);
|
||||
} else
|
||||
memcpy(dire, directory_table + bytes,
|
||||
sizeof(*dire));
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_opendir: directory entry %s, inode "
|
||||
"%d:%d, type %d\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
if((dir->dir_count % DIR_ENT_SIZE) == 0) {
|
||||
new_dir = realloc(dir->dirs, (dir->dir_count +
|
||||
DIR_ENT_SIZE) * sizeof(struct dir_ent));
|
||||
if(new_dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: "
|
||||
"realloc failed!\n");
|
||||
dir->dirs = new_dir;
|
||||
}
|
||||
strcpy(dir->dirs[dir->dir_count].name, dire->name);
|
||||
dir->dirs[dir->dir_count].start_block =
|
||||
dirh.start_block;
|
||||
dir->dirs[dir->dir_count].offset = dire->offset;
|
||||
dir->dirs[dir->dir_count].type = dire->type;
|
||||
dir->dir_count ++;
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
||||
corrupted:
|
||||
free(dir->dirs);
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int parse_exports_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.inodes is 2^32 (unsigned int)
|
||||
* Max indexes is (2^32*8)/8K or 2^22
|
||||
* Max length is ((2^32*8)/8K)*8 or 2^25
|
||||
*/
|
||||
int res;
|
||||
int indexes = SQUASHFS_LOOKUP_BLOCKS_3((long long) sBlk.s.inodes);
|
||||
int length = SQUASHFS_LOOKUP_BLOCK_BYTES_3((long long) sBlk.s.inodes);
|
||||
long long *export_index_table;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start - sBlk.s.lookup_table_start)) {
|
||||
ERROR("parse_exports_table: Bad inode count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
export_index_table = alloc_index_table(indexes);
|
||||
|
||||
if(swap) {
|
||||
long long *sexport_index_table = salloc_index_table(indexes);
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.lookup_table_start,
|
||||
length, sexport_index_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("parse_exorts_table: failed to read export "
|
||||
"index table\n");
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_SWAP_LOOKUP_BLOCKS_3(export_index_table,
|
||||
sexport_index_table, indexes);
|
||||
} else {
|
||||
res = read_fs_bytes(fd, sBlk.s.lookup_table_start, length,
|
||||
export_index_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("parse_exorts_table: failed to read export "
|
||||
"index table\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* export_index_table[0] stores the start of the compressed export blocks.
|
||||
* This by definition is also the end of the previous filesystem
|
||||
* table - the fragment table.
|
||||
*/
|
||||
*table_start = export_index_table[0];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
squashfs_operations *read_filesystem_tables_3()
|
||||
{
|
||||
long long table_start;
|
||||
|
||||
/* Read uid and gid lookup tables */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.no_guids) {
|
||||
if(sBlk.guid_start >= sBlk.s.bytes_used) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_guids, sBlk.guid_start, sBlk.s.bytes_used, &guid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.guid_start;
|
||||
} else {
|
||||
/* no guids, guid_start should be 0 */
|
||||
if(sBlk.guid_start != 0) {
|
||||
ERROR("read_filesystem_tables: gid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
table_start = sBlk.s.bytes_used;
|
||||
}
|
||||
|
||||
if(sBlk.uid_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: uid start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* There should be at least one uid */
|
||||
if(sBlk.no_uids == 0) {
|
||||
ERROR("read_filesystem_tables: uid count bad in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_ids(sBlk.no_uids, sBlk.uid_start, table_start, &uid_table) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
table_start = sBlk.uid_start;
|
||||
|
||||
/* Read exports table */
|
||||
if(sBlk.s.lookup_table_start != SQUASHFS_INVALID_BLK) {
|
||||
|
||||
/* sanity check super block contents */
|
||||
if(sBlk.s.lookup_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: lookup table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(parse_exports_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* Read fragment table */
|
||||
if(sBlk.s.fragments != 0) {
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.fragment_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* The number of fragments should not exceed the number of inodes */
|
||||
if(sBlk.s.fragments > sBlk.s.inodes) {
|
||||
ERROR("read_filesystem_tables: Bad fragment count in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_fragment_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
} else {
|
||||
/*
|
||||
* Sanity check super block contents - with 0 fragments,
|
||||
* the fragment table should be empty
|
||||
*/
|
||||
if(sBlk.s.fragment_table_start != table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start invalid in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read directory table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.directory_table_start > table_start) {
|
||||
ERROR("read_filesystem_tables: directory table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
directory_table = read_directory_table(sBlk.s.directory_table_start,
|
||||
table_start);
|
||||
if(directory_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
/* Read inode table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
|
||||
ERROR("read_filesystem_tables: inode table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
inode_table = read_inode_table(sBlk.s.inode_table_start,
|
||||
sBlk.s.directory_table_start);
|
||||
if(inode_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
alloc_index_table(0);
|
||||
salloc_index_table(0);
|
||||
|
||||
return &ops;
|
||||
|
||||
corrupted:
|
||||
ERROR("File system corruption detected\n");
|
||||
alloc_index_table(0);
|
||||
salloc_index_table(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static squashfs_operations ops = {
|
||||
.opendir = squashfs_opendir,
|
||||
.read_fragment = read_fragment,
|
||||
.read_block_list = read_block_list,
|
||||
.read_inode = read_inode
|
||||
};
|
47
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-34.c
Normal file
47
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-34.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-34.c
|
||||
*
|
||||
* Helper functions used by unsquash-3 and unsquash-4.
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
|
||||
long long *alloc_index_table(int indexes)
|
||||
{
|
||||
static long long *alloc_table = NULL;
|
||||
static int alloc_size = 0;
|
||||
int length = indexes * sizeof(long long);
|
||||
|
||||
if(alloc_size < length || length == 0) {
|
||||
long long *table = realloc(alloc_table, length);
|
||||
|
||||
if(table == NULL && length !=0)
|
||||
EXIT_UNSQUASH("alloc_index_table: failed to allocate "
|
||||
"index table\n");
|
||||
|
||||
alloc_table = table;
|
||||
alloc_size = length;
|
||||
}
|
||||
|
||||
return alloc_table;
|
||||
}
|
621
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-4.c
Normal file
621
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquash-4.c
Normal file
|
@ -0,0 +1,621 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquash-4.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "squashfs_swap.h"
|
||||
#include "xattr.h"
|
||||
|
||||
static struct squashfs_fragment_entry *fragment_table;
|
||||
static unsigned int *id_table;
|
||||
static char *inode_table, *directory_table;
|
||||
static squashfs_operations ops;
|
||||
|
||||
static void read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
|
||||
{
|
||||
TRACE("read_block_list: blocks %d\n", blocks);
|
||||
|
||||
memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
|
||||
SQUASHFS_INSWAP_INTS(block_list, blocks);
|
||||
}
|
||||
|
||||
|
||||
static int read_fragment_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.fragments is 2^32 (unsigned int)
|
||||
* Max size of bytes is 2^32*16 or 2^36
|
||||
* Max indexes is (2^32*16)/8K or 2^23
|
||||
* Max length is ((2^32*16)/8K)*8 or 2^26 or 64M
|
||||
*/
|
||||
int res, i;
|
||||
long long bytes = SQUASHFS_FRAGMENT_BYTES((long long) sBlk.s.fragments);
|
||||
int indexes = SQUASHFS_FRAGMENT_INDEXES((long long) sBlk.s.fragments);
|
||||
int length = SQUASHFS_FRAGMENT_INDEX_BYTES((long long) sBlk.s.fragments);
|
||||
long long *fragment_table_index;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start - sBlk.s.fragment_table_start)) {
|
||||
ERROR("read_fragment_table: Bad fragment count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
|
||||
"from 0x%llx\n", sBlk.s.fragments, indexes,
|
||||
sBlk.s.fragment_table_start);
|
||||
|
||||
fragment_table_index = alloc_index_table(indexes);
|
||||
fragment_table = malloc(bytes);
|
||||
if(fragment_table == NULL)
|
||||
EXIT_UNSQUASH("read_fragment_table: failed to allocate "
|
||||
"fragment table\n");
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.fragment_table_start, length,
|
||||
fragment_table_index);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment table "
|
||||
"index\n");
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes);
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
int length = read_block(fd, fragment_table_index[i], NULL,
|
||||
expected, ((char *) fragment_table) + (i *
|
||||
SQUASHFS_METADATA_SIZE));
|
||||
TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
|
||||
i, fragment_table_index[i], length);
|
||||
if(length == FALSE) {
|
||||
ERROR("read_fragment_table: failed to read fragment "
|
||||
"table index\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < sBlk.s.fragments; i++)
|
||||
SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
|
||||
|
||||
*table_start = fragment_table_index[0];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void read_fragment(unsigned int fragment, long long *start_block, int *size)
|
||||
{
|
||||
TRACE("read_fragment: reading fragment %d\n", fragment);
|
||||
|
||||
struct squashfs_fragment_entry *fragment_entry;
|
||||
|
||||
fragment_entry = &fragment_table[fragment];
|
||||
*start_block = fragment_entry->start_block;
|
||||
*size = fragment_entry->size;
|
||||
}
|
||||
|
||||
|
||||
static struct inode *read_inode(unsigned int start_block, unsigned int offset)
|
||||
{
|
||||
static union squashfs_inode_header header;
|
||||
long long start = sBlk.s.inode_table_start + start_block;
|
||||
long long bytes = lookup_entry(inode_table_hash, start);
|
||||
char *block_ptr = inode_table + bytes + offset;
|
||||
static struct inode i;
|
||||
|
||||
TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
|
||||
start);
|
||||
|
||||
SQUASHFS_SWAP_BASE_INODE_HEADER(block_ptr, &header.base);
|
||||
|
||||
i.uid = (uid_t) id_table[header.base.uid];
|
||||
i.gid = (uid_t) id_table[header.base.guid];
|
||||
i.mode = lookup_type[header.base.inode_type] | header.base.mode;
|
||||
i.type = header.base.inode_type;
|
||||
i.time = header.base.mtime;
|
||||
i.inode_number = header.base.inode_number;
|
||||
|
||||
switch(header.base.inode_type) {
|
||||
case SQUASHFS_DIR_TYPE: {
|
||||
struct squashfs_dir_inode_header *inode = &header.dir;
|
||||
|
||||
SQUASHFS_SWAP_DIR_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LDIR_TYPE: {
|
||||
struct squashfs_ldir_inode_header *inode = &header.ldir;
|
||||
|
||||
SQUASHFS_SWAP_LDIR_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.offset = inode->offset;
|
||||
i.start = inode->start_block;
|
||||
i.xattr = inode->xattr;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FILE_TYPE: {
|
||||
struct squashfs_reg_inode_header *inode = &header.reg;
|
||||
|
||||
SQUASHFS_SWAP_REG_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
|
||||
? 0 : inode->file_size % sBlk.s.block_size;
|
||||
i.fragment = inode->fragment;
|
||||
i.offset = inode->offset;
|
||||
i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(i.data + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log :
|
||||
i.data >> sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.sparse = 0;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LREG_TYPE: {
|
||||
struct squashfs_lreg_inode_header *inode = &header.lreg;
|
||||
|
||||
SQUASHFS_SWAP_LREG_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = inode->file_size;
|
||||
i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
|
||||
? 0 : inode->file_size % sBlk.s.block_size;
|
||||
i.fragment = inode->fragment;
|
||||
i.offset = inode->offset;
|
||||
i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
|
||||
(inode->file_size + sBlk.s.block_size - 1) >>
|
||||
sBlk.s.block_log :
|
||||
inode->file_size >> sBlk.s.block_log;
|
||||
i.start = inode->start_block;
|
||||
i.sparse = inode->sparse != 0;
|
||||
i.block_ptr = block_ptr + sizeof(*inode);
|
||||
i.xattr = inode->xattr;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_SYMLINK_TYPE:
|
||||
case SQUASHFS_LSYMLINK_TYPE: {
|
||||
struct squashfs_symlink_inode_header *inode = &header.symlink;
|
||||
|
||||
SQUASHFS_SWAP_SYMLINK_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.symlink = malloc(inode->symlink_size + 1);
|
||||
if(i.symlink == NULL)
|
||||
EXIT_UNSQUASH("read_inode: failed to malloc "
|
||||
"symlink data\n");
|
||||
strncpy(i.symlink, block_ptr +
|
||||
sizeof(struct squashfs_symlink_inode_header),
|
||||
inode->symlink_size);
|
||||
i.symlink[inode->symlink_size] = '\0';
|
||||
i.data = inode->symlink_size;
|
||||
|
||||
if(header.base.inode_type == SQUASHFS_LSYMLINK_TYPE)
|
||||
SQUASHFS_SWAP_INTS(block_ptr +
|
||||
sizeof(struct squashfs_symlink_inode_header) +
|
||||
inode->symlink_size, &i.xattr, 1);
|
||||
else
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
struct squashfs_dev_inode_header *inode = &header.dev;
|
||||
|
||||
SQUASHFS_SWAP_DEV_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = inode->rdev;
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LBLKDEV_TYPE:
|
||||
case SQUASHFS_LCHRDEV_TYPE: {
|
||||
struct squashfs_ldev_inode_header *inode = &header.ldev;
|
||||
|
||||
SQUASHFS_SWAP_LDEV_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = inode->rdev;
|
||||
i.xattr = inode->xattr;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
i.data = 0;
|
||||
i.xattr = SQUASHFS_INVALID_XATTR;
|
||||
break;
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
case SQUASHFS_LSOCKET_TYPE: {
|
||||
struct squashfs_lipc_inode_header *inode = &header.lipc;
|
||||
|
||||
SQUASHFS_SWAP_LIPC_INODE_HEADER(block_ptr, inode);
|
||||
|
||||
i.data = 0;
|
||||
i.xattr = inode->xattr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
EXIT_UNSQUASH("Unknown inode type %d in read_inode!\n",
|
||||
header.base.inode_type);
|
||||
}
|
||||
return &i;
|
||||
}
|
||||
|
||||
|
||||
static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset,
|
||||
struct inode **i)
|
||||
{
|
||||
struct squashfs_dir_header dirh;
|
||||
char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]
|
||||
__attribute__((aligned));
|
||||
struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
|
||||
long long start;
|
||||
long long bytes;
|
||||
int dir_count, size;
|
||||
struct dir_ent *new_dir;
|
||||
struct dir *dir;
|
||||
|
||||
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
|
||||
block_start, offset);
|
||||
|
||||
*i = read_inode(block_start, offset);
|
||||
|
||||
dir = malloc(sizeof(struct dir));
|
||||
if(dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
|
||||
|
||||
dir->dir_count = 0;
|
||||
dir->cur_entry = 0;
|
||||
dir->mode = (*i)->mode;
|
||||
dir->uid = (*i)->uid;
|
||||
dir->guid = (*i)->gid;
|
||||
dir->mtime = (*i)->time;
|
||||
dir->xattr = (*i)->xattr;
|
||||
dir->dirs = NULL;
|
||||
|
||||
if ((*i)->data == 3)
|
||||
/*
|
||||
* if the directory is empty, skip the unnecessary
|
||||
* lookup_entry, this fixes the corner case with
|
||||
* completely empty filesystems where lookup_entry correctly
|
||||
* returning -1 is incorrectly treated as an error
|
||||
*/
|
||||
return dir;
|
||||
|
||||
start = sBlk.s.directory_table_start + (*i)->start;
|
||||
bytes = lookup_entry(directory_table_hash, start);
|
||||
|
||||
if(bytes == -1)
|
||||
EXIT_UNSQUASH("squashfs_opendir: directory block %lld not "
|
||||
"found!\n", start);
|
||||
|
||||
bytes += (*i)->offset;
|
||||
size = (*i)->data + bytes - 3;
|
||||
|
||||
while(bytes < size) {
|
||||
SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
|
||||
|
||||
dir_count = dirh.count + 1;
|
||||
TRACE("squashfs_opendir: Read directory header @ byte position "
|
||||
"%d, %d directory entries\n", bytes, dir_count);
|
||||
bytes += sizeof(dirh);
|
||||
|
||||
/* dir_count should never be larger than SQUASHFS_DIR_COUNT */
|
||||
if(dir_count > SQUASHFS_DIR_COUNT) {
|
||||
ERROR("File system corrupted: too many entries in directory\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
while(dir_count--) {
|
||||
SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
|
||||
|
||||
bytes += sizeof(*dire);
|
||||
|
||||
/* size should never be SQUASHFS_NAME_LEN or larger */
|
||||
if(dire->size >= SQUASHFS_NAME_LEN) {
|
||||
ERROR("File system corrupted: filename too long\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
memcpy(dire->name, directory_table + bytes,
|
||||
dire->size + 1);
|
||||
dire->name[dire->size + 1] = '\0';
|
||||
TRACE("squashfs_opendir: directory entry %s, inode "
|
||||
"%d:%d, type %d\n", dire->name,
|
||||
dirh.start_block, dire->offset, dire->type);
|
||||
if((dir->dir_count % DIR_ENT_SIZE) == 0) {
|
||||
new_dir = realloc(dir->dirs, (dir->dir_count +
|
||||
DIR_ENT_SIZE) * sizeof(struct dir_ent));
|
||||
if(new_dir == NULL)
|
||||
EXIT_UNSQUASH("squashfs_opendir: "
|
||||
"realloc failed!\n");
|
||||
dir->dirs = new_dir;
|
||||
}
|
||||
strcpy(dir->dirs[dir->dir_count].name, dire->name);
|
||||
dir->dirs[dir->dir_count].start_block =
|
||||
dirh.start_block;
|
||||
dir->dirs[dir->dir_count].offset = dire->offset;
|
||||
dir->dirs[dir->dir_count].type = dire->type;
|
||||
dir->dir_count ++;
|
||||
bytes += dire->size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
|
||||
corrupted:
|
||||
free(dir->dirs);
|
||||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int read_id_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.no_ids is 2^16 (unsigned short)
|
||||
* Max size of bytes is 2^16*4 or 256K
|
||||
* Max indexes is (2^16*4)/8K or 32
|
||||
* Max length is ((2^16*4)/8K)*8 or 256
|
||||
*/
|
||||
int res, i;
|
||||
int bytes = SQUASHFS_ID_BYTES(sBlk.s.no_ids);
|
||||
int indexes = SQUASHFS_ID_BLOCKS(sBlk.s.no_ids);
|
||||
int length = SQUASHFS_ID_BLOCK_BYTES(sBlk.s.no_ids);
|
||||
long long *id_index_table;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start - sBlk.s.id_table_start)) {
|
||||
ERROR("read_id_table: Bad id count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE("read_id_table: no_ids %d\n", sBlk.s.no_ids);
|
||||
|
||||
id_index_table = alloc_index_table(indexes);
|
||||
id_table = malloc(bytes);
|
||||
if(id_table == NULL) {
|
||||
ERROR("read_id_table: failed to allocate id table\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.id_table_start, length, id_index_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_id_table: failed to read id index table\n");
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_INSWAP_ID_BLOCKS(id_index_table, indexes);
|
||||
|
||||
/*
|
||||
* id_index_table[0] stores the start of the compressed id blocks.
|
||||
* This by definition is also the end of the previous filesystem
|
||||
* table - this may be the exports table if it is present, or the
|
||||
* fragments table if it isn't.
|
||||
*/
|
||||
*table_start = id_index_table[0];
|
||||
|
||||
for(i = 0; i < indexes; i++) {
|
||||
int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
|
||||
bytes & (SQUASHFS_METADATA_SIZE - 1);
|
||||
res = read_block(fd, id_index_table[i], NULL, expected,
|
||||
((char *) id_table) + i * SQUASHFS_METADATA_SIZE);
|
||||
if(res == FALSE) {
|
||||
ERROR("read_id_table: failed to read id table block"
|
||||
"\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
SQUASHFS_INSWAP_INTS(id_table, sBlk.s.no_ids);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static int parse_exports_table(long long *table_start)
|
||||
{
|
||||
/*
|
||||
* Note on overflow limits:
|
||||
* Size of SBlk.s.inodes is 2^32 (unsigned int)
|
||||
* Max indexes is (2^32*8)/8K or 2^22
|
||||
* Max length is ((2^32*8)/8K)*8 or 2^25
|
||||
*/
|
||||
int res;
|
||||
int indexes = SQUASHFS_LOOKUP_BLOCKS((long long) sBlk.s.inodes);
|
||||
int length = SQUASHFS_LOOKUP_BLOCK_BYTES((long long) sBlk.s.inodes);
|
||||
long long *export_index_table;
|
||||
|
||||
/*
|
||||
* The size of the index table (length bytes) should match the
|
||||
* table start and end points
|
||||
*/
|
||||
if(length != (*table_start - sBlk.s.lookup_table_start)) {
|
||||
ERROR("parse_exports_table: Bad inode count in super block\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
export_index_table = alloc_index_table(indexes);
|
||||
|
||||
res = read_fs_bytes(fd, sBlk.s.lookup_table_start, length,
|
||||
export_index_table);
|
||||
if(res == FALSE) {
|
||||
ERROR("parse_exports_table: failed to read export index table\n");
|
||||
return FALSE;
|
||||
}
|
||||
SQUASHFS_INSWAP_LOOKUP_BLOCKS(export_index_table, indexes);
|
||||
|
||||
/*
|
||||
* export_index_table[0] stores the start of the compressed export blocks.
|
||||
* This by definition is also the end of the previous filesystem
|
||||
* table - the fragment table.
|
||||
*/
|
||||
*table_start = export_index_table[0];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
squashfs_operations *read_filesystem_tables_4()
|
||||
{
|
||||
long long table_start;
|
||||
|
||||
/* Read xattrs */
|
||||
if(sBlk.s.xattr_id_table_start != SQUASHFS_INVALID_BLK) {
|
||||
/* sanity check super block contents */
|
||||
if(sBlk.s.xattr_id_table_start >= sBlk.s.bytes_used) {
|
||||
ERROR("read_filesystem_tables: xattr id table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_xattrs_from_disk(fd, &sBlk.s, no_xattrs, &table_start) == 0)
|
||||
goto corrupted;
|
||||
} else
|
||||
table_start = sBlk.s.bytes_used;
|
||||
|
||||
/* Read id lookup table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.id_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: id table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* there should always be at least one id */
|
||||
if(sBlk.s.no_ids == 0) {
|
||||
ERROR("read_filesystem_tables: Bad id count in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/*
|
||||
* the number of ids can never be more than double the number of inodes
|
||||
* (the maximum is a unique uid and gid for each inode).
|
||||
*/
|
||||
if(sBlk.s.no_ids > (sBlk.s.inodes * 2L)) {
|
||||
ERROR("read_filesystem_tables: Bad id count in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_id_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
|
||||
/* Read exports table */
|
||||
if(sBlk.s.lookup_table_start != SQUASHFS_INVALID_BLK) {
|
||||
|
||||
/* sanity check super block contents */
|
||||
if(sBlk.s.lookup_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: lookup table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(parse_exports_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* Read fragment table */
|
||||
if(sBlk.s.fragments != 0) {
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.fragment_table_start >= table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
/* The number of fragments should not exceed the number of inodes */
|
||||
if(sBlk.s.fragments > sBlk.s.inodes) {
|
||||
ERROR("read_filesystem_tables: Bad fragment count in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
if(read_fragment_table(&table_start) == FALSE)
|
||||
goto corrupted;
|
||||
} else {
|
||||
/*
|
||||
* Sanity check super block contents - with 0 fragments,
|
||||
* the fragment table should be empty
|
||||
*/
|
||||
if(sBlk.s.fragment_table_start != table_start) {
|
||||
ERROR("read_filesystem_tables: fragment table start invalid in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read directory table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.directory_table_start > table_start) {
|
||||
ERROR("read_filesystem_tables: directory table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
directory_table = read_directory_table(sBlk.s.directory_table_start,
|
||||
table_start);
|
||||
if(directory_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
/* Read inode table */
|
||||
|
||||
/* Sanity check super block contents */
|
||||
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
|
||||
ERROR("read_filesystem_tables: inode table start too large in super block\n");
|
||||
goto corrupted;
|
||||
}
|
||||
|
||||
inode_table = read_inode_table(sBlk.s.inode_table_start,
|
||||
sBlk.s.directory_table_start);
|
||||
if(inode_table == NULL)
|
||||
goto corrupted;
|
||||
|
||||
if(no_xattrs)
|
||||
sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
|
||||
|
||||
alloc_index_table(0);
|
||||
|
||||
return &ops;
|
||||
|
||||
corrupted:
|
||||
ERROR("File system corruption detected\n");
|
||||
alloc_index_table(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static squashfs_operations ops = {
|
||||
.opendir = squashfs_opendir,
|
||||
.read_fragment = read_fragment,
|
||||
.read_block_list = read_block_list,
|
||||
.read_inode = read_inode
|
||||
};
|
3159
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs.c
Normal file
3159
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs.c
Normal file
File diff suppressed because it is too large
Load diff
264
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs.h
Normal file
264
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs.h
Normal file
|
@ -0,0 +1,264 @@
|
|||
#ifndef UNSQUASHFS_H
|
||||
#define UNSQUASHFS_H
|
||||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2009, 2010, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquashfs.h
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <utime.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <time.h>
|
||||
#include <regex.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <math.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "error.h"
|
||||
|
||||
#define CALCULATE_HASH(start) (start & 0xffff)
|
||||
|
||||
/*
|
||||
* Unified superblock containing fields for all superblocks
|
||||
*/
|
||||
struct super_block {
|
||||
struct squashfs_super_block s;
|
||||
/* fields only used by squashfs 3 and earlier layouts */
|
||||
unsigned int no_uids;
|
||||
unsigned int no_guids;
|
||||
long long uid_start;
|
||||
long long guid_start;
|
||||
};
|
||||
|
||||
struct hash_table_entry {
|
||||
long long start;
|
||||
long long bytes;
|
||||
struct hash_table_entry *next;
|
||||
};
|
||||
|
||||
struct inode {
|
||||
int blocks;
|
||||
char *block_ptr;
|
||||
long long data;
|
||||
int fragment;
|
||||
int frag_bytes;
|
||||
gid_t gid;
|
||||
int inode_number;
|
||||
int mode;
|
||||
int offset;
|
||||
long long start;
|
||||
char *symlink;
|
||||
time_t time;
|
||||
int type;
|
||||
uid_t uid;
|
||||
char sparse;
|
||||
unsigned int xattr;
|
||||
};
|
||||
|
||||
typedef struct squashfs_operations {
|
||||
struct dir *(*opendir)(unsigned int block_start,
|
||||
unsigned int offset, struct inode **i);
|
||||
void (*read_fragment)(unsigned int fragment, long long *start_block,
|
||||
int *size);
|
||||
void (*read_block_list)(unsigned int *block_list, char *block_ptr,
|
||||
int blocks);
|
||||
struct inode *(*read_inode)(unsigned int start_block,
|
||||
unsigned int offset);
|
||||
} squashfs_operations;
|
||||
|
||||
struct test {
|
||||
int mask;
|
||||
int value;
|
||||
int position;
|
||||
char mode;
|
||||
};
|
||||
|
||||
|
||||
/* Cache status struct. Caches are used to keep
|
||||
track of memory buffers passed between different threads */
|
||||
struct cache {
|
||||
int max_buffers;
|
||||
int count;
|
||||
int used;
|
||||
int buffer_size;
|
||||
int wait_free;
|
||||
int wait_pending;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t wait_for_free;
|
||||
pthread_cond_t wait_for_pending;
|
||||
struct cache_entry *free_list;
|
||||
struct cache_entry *hash_table[65536];
|
||||
};
|
||||
|
||||
/* struct describing a cache entry passed between threads */
|
||||
struct cache_entry {
|
||||
struct cache *cache;
|
||||
long long block;
|
||||
int size;
|
||||
int used;
|
||||
int error;
|
||||
int pending;
|
||||
struct cache_entry *hash_next;
|
||||
struct cache_entry *hash_prev;
|
||||
struct cache_entry *free_next;
|
||||
struct cache_entry *free_prev;
|
||||
char *data;
|
||||
};
|
||||
|
||||
/* struct describing queues used to pass data between threads */
|
||||
struct queue {
|
||||
int size;
|
||||
int readp;
|
||||
int writep;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t empty;
|
||||
pthread_cond_t full;
|
||||
void **data;
|
||||
};
|
||||
|
||||
/* default size of fragment buffer in Mbytes */
|
||||
#define FRAGMENT_BUFFER_DEFAULT 256
|
||||
/* default size of data buffer in Mbytes */
|
||||
#define DATA_BUFFER_DEFAULT 256
|
||||
|
||||
#define DIR_ENT_SIZE 16
|
||||
|
||||
struct dir_ent {
|
||||
char name[SQUASHFS_NAME_LEN + 1];
|
||||
unsigned int start_block;
|
||||
unsigned int offset;
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
struct dir {
|
||||
int dir_count;
|
||||
int cur_entry;
|
||||
unsigned int mode;
|
||||
uid_t uid;
|
||||
gid_t guid;
|
||||
unsigned int mtime;
|
||||
unsigned int xattr;
|
||||
struct dir_ent *dirs;
|
||||
};
|
||||
|
||||
struct file_entry {
|
||||
int offset;
|
||||
int size;
|
||||
struct cache_entry *buffer;
|
||||
};
|
||||
|
||||
|
||||
struct squashfs_file {
|
||||
int fd;
|
||||
int blocks;
|
||||
long long file_size;
|
||||
int mode;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
time_t time;
|
||||
char *pathname;
|
||||
char sparse;
|
||||
unsigned int xattr;
|
||||
};
|
||||
|
||||
struct path_entry {
|
||||
char *name;
|
||||
regex_t *preg;
|
||||
struct pathname *paths;
|
||||
};
|
||||
|
||||
struct pathname {
|
||||
int names;
|
||||
struct path_entry *name;
|
||||
};
|
||||
|
||||
struct pathnames {
|
||||
int count;
|
||||
struct pathname *path[0];
|
||||
};
|
||||
#define PATHS_ALLOC_SIZE 10
|
||||
|
||||
/* globals */
|
||||
extern struct super_block sBlk;
|
||||
extern int swap;
|
||||
extern struct hash_table_entry *inode_table_hash[65536],
|
||||
*directory_table_hash[65536];
|
||||
extern pthread_mutex_t screen_mutex;
|
||||
extern int progress_enabled;
|
||||
extern int inode_number;
|
||||
extern int lookup_type[];
|
||||
extern int fd;
|
||||
extern int no_xattrs;
|
||||
extern struct queue *to_reader, *to_inflate, *to_writer;
|
||||
extern struct cache *fragment_cache, *data_cache;
|
||||
|
||||
/* unsquashfs.c */
|
||||
extern void *read_inode_table(long long, long long);
|
||||
extern void *read_directory_table(long long, long long);
|
||||
extern long long lookup_entry(struct hash_table_entry **, long long);
|
||||
extern int read_fs_bytes(int fd, long long, int, void *);
|
||||
extern int read_block(int, long long, long long *, int, void *);
|
||||
extern void enable_progress_bar();
|
||||
extern void disable_progress_bar();
|
||||
extern void dump_queue(struct queue *);
|
||||
extern void dump_cache(struct cache *);
|
||||
|
||||
/* unsquash-1.c */
|
||||
extern squashfs_operations *read_filesystem_tables_1();
|
||||
|
||||
/* unsquash-2.c */
|
||||
extern squashfs_operations *read_filesystem_tables_2();
|
||||
|
||||
/* unsquash-3.c */
|
||||
extern squashfs_operations *read_filesystem_tables_3();
|
||||
|
||||
/* unsquash-4.c */
|
||||
extern squashfs_operations *read_filesystem_tables_4();
|
||||
|
||||
/* unsquash-123.c */
|
||||
extern int read_ids(int, long long, long long, unsigned int **);
|
||||
|
||||
/* unsquash-34.c */
|
||||
extern long long *alloc_index_table(int);
|
||||
#endif
|
145
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs_info.c
Normal file
145
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs_info.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquashfs_info.c
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "unsquashfs.h"
|
||||
#include "error.h"
|
||||
|
||||
static int silent = 0;
|
||||
char *pathname = NULL;
|
||||
|
||||
pthread_t info_thread;
|
||||
|
||||
|
||||
void disable_info()
|
||||
{
|
||||
if(pathname)
|
||||
free(pathname);
|
||||
|
||||
pathname = NULL;
|
||||
}
|
||||
|
||||
|
||||
void update_info(char *name)
|
||||
{
|
||||
if(pathname)
|
||||
free(pathname);
|
||||
|
||||
pathname = name;
|
||||
}
|
||||
|
||||
|
||||
void dump_state()
|
||||
{
|
||||
disable_progress_bar();
|
||||
|
||||
printf("Queue and cache status dump\n");
|
||||
printf("===========================\n");
|
||||
|
||||
printf("file buffer read queue (main thread -> reader thread)\n");
|
||||
dump_queue(to_reader);
|
||||
|
||||
printf("file buffer decompress queue (reader thread -> inflate"
|
||||
" thread(s))\n");
|
||||
dump_queue(to_inflate);
|
||||
|
||||
printf("file buffer write queue (main thread -> writer thread)\n");
|
||||
dump_queue(to_writer);
|
||||
|
||||
printf("\nbuffer cache (uncompressed blocks and compressed blocks "
|
||||
"'in flight')\n");
|
||||
dump_cache(data_cache);
|
||||
|
||||
printf("fragment buffer cache (uncompressed frags and compressed"
|
||||
" frags 'in flight')\n");
|
||||
dump_cache(fragment_cache);
|
||||
|
||||
enable_progress_bar();
|
||||
}
|
||||
|
||||
|
||||
void *info_thrd(void *arg)
|
||||
{
|
||||
sigset_t sigmask;
|
||||
struct timespec timespec = { .tv_sec = 1, .tv_nsec = 0 };
|
||||
int sig, waiting = 0;
|
||||
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGQUIT);
|
||||
sigaddset(&sigmask, SIGHUP);
|
||||
|
||||
while(1) {
|
||||
if(waiting)
|
||||
sig = sigtimedwait(&sigmask, NULL, ×pec);
|
||||
else
|
||||
sig = sigwaitinfo(&sigmask, NULL);
|
||||
|
||||
if(sig == -1) {
|
||||
switch(errno) {
|
||||
case EAGAIN:
|
||||
/* interval timed out */
|
||||
waiting = 0;
|
||||
/* FALLTHROUGH */
|
||||
case EINTR:
|
||||
/* if waiting, the wait will be longer, but
|
||||
that's OK */
|
||||
continue;
|
||||
default:
|
||||
BAD_ERROR("sigtimedwait/sigwaitinfo failed "
|
||||
"because %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if(sig == SIGQUIT && !waiting) {
|
||||
if(pathname)
|
||||
INFO("%s\n", pathname);
|
||||
|
||||
/* set one second interval period, if ^\ received
|
||||
within then, dump queue and cache status */
|
||||
waiting = 1;
|
||||
} else
|
||||
dump_state();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_info()
|
||||
{
|
||||
pthread_create(&info_thread, NULL, info_thrd, NULL);
|
||||
}
|
30
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs_info.h
Normal file
30
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs_info.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef UNSQUASHFS_INFO_H
|
||||
#define UNSQUASHFS_INFO_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2013, 2014
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquashfs_info.h
|
||||
*/
|
||||
|
||||
extern void disable_info();
|
||||
extern void update_info(char *);
|
||||
extern void init_info();
|
||||
#endif
|
144
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs_xattr.c
Normal file
144
SQUASHFS/squashfs-tools-4.4/squashfs-tools/unsquashfs_xattr.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Unsquash a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2010, 2012, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* unsquashfs_xattr.c
|
||||
*/
|
||||
|
||||
#include "unsquashfs.h"
|
||||
#include "xattr.h"
|
||||
|
||||
#include <sys/xattr.h>
|
||||
|
||||
#define NOSPACE_MAX 10
|
||||
|
||||
extern int root_process;
|
||||
extern int user_xattrs;
|
||||
extern int ignore_errors;
|
||||
extern int strict_errors;
|
||||
|
||||
int write_xattr(char *pathname, unsigned int xattr)
|
||||
{
|
||||
unsigned int count;
|
||||
struct xattr_list *xattr_list;
|
||||
int i;
|
||||
static int nonsuper_error = FALSE;
|
||||
static int ignore_xattrs = FALSE;
|
||||
static int nospace_error = 0;
|
||||
int failed;
|
||||
|
||||
if(ignore_xattrs || xattr == SQUASHFS_INVALID_XATTR ||
|
||||
sBlk.s.xattr_id_table_start == SQUASHFS_INVALID_BLK)
|
||||
return TRUE;
|
||||
|
||||
xattr_list = get_xattr(xattr, &count, &failed);
|
||||
if(failed)
|
||||
EXIT_UNSQUASH_STRICT("write_xattr: Failed to read one or more xattrs for %s\n", pathname);
|
||||
|
||||
for(i = 0; i < count; i++) {
|
||||
int prefix = xattr_list[i].type & SQUASHFS_XATTR_PREFIX_MASK;
|
||||
|
||||
if(ignore_xattrs || (user_xattrs && prefix != SQUASHFS_XATTR_USER))
|
||||
continue;
|
||||
|
||||
if(root_process || prefix == SQUASHFS_XATTR_USER) {
|
||||
int res = lsetxattr(pathname, xattr_list[i].full_name,
|
||||
xattr_list[i].value, xattr_list[i].vsize, 0);
|
||||
|
||||
if(res == -1) {
|
||||
if(errno == ENOTSUP) {
|
||||
/*
|
||||
* If the destination filesystem cannot
|
||||
* suppport xattrs, print error, and
|
||||
* disable xattr output as this error is
|
||||
* unlikely to go away, and printing
|
||||
* screenfulls of the same error message
|
||||
* is rather annoying
|
||||
*/
|
||||
ERROR("write_xattr: failed to write "
|
||||
"xattr %s for file %s because "
|
||||
"extended attributes are not "
|
||||
"supported by the destination "
|
||||
"filesystem\n",
|
||||
xattr_list[i].full_name,
|
||||
pathname);
|
||||
ERROR("Ignoring xattrs in "
|
||||
"filesystem\n");
|
||||
EXIT_UNSQUASH_STRICT("To avoid this error message, "
|
||||
"specify -no-xattrs\n");
|
||||
ignore_xattrs = TRUE;
|
||||
} else if((errno == ENOSPC || errno == EDQUOT)
|
||||
&& nospace_error < NOSPACE_MAX) {
|
||||
/*
|
||||
* Many filesystems like ext2/3/4 have
|
||||
* limits on the amount of xattr
|
||||
* data that can be stored per file
|
||||
* (typically one block or 4K), so
|
||||
* we shouldn't disable xattr ouput,
|
||||
* as the error may be restriced to one
|
||||
* file only. If we get a lot of these
|
||||
* then suppress the error messsage
|
||||
*/
|
||||
EXIT_UNSQUASH_IGNORE("write_xattr: failed to write "
|
||||
"xattr %s for file %s because "
|
||||
"no extended attribute space "
|
||||
"remaining (per file or "
|
||||
"filesystem limit)\n",
|
||||
xattr_list[i].full_name,
|
||||
pathname);
|
||||
if(++ nospace_error == NOSPACE_MAX)
|
||||
ERROR("%d of these errors "
|
||||
"printed, further error "
|
||||
"messages of this type "
|
||||
"are suppressed!\n",
|
||||
NOSPACE_MAX);
|
||||
} else
|
||||
EXIT_UNSQUASH_IGNORE("write_xattr: failed to write "
|
||||
"xattr %s for file %s because "
|
||||
"%s\n", xattr_list[i].full_name,
|
||||
pathname, strerror(errno));
|
||||
failed = TRUE;
|
||||
}
|
||||
} else if(nonsuper_error == FALSE) {
|
||||
/*
|
||||
* if extract user xattrs only then
|
||||
* error message is suppressed, if not
|
||||
* print error, and then suppress further error
|
||||
* messages to avoid possible screenfulls of the
|
||||
* same error message!
|
||||
*/
|
||||
ERROR("write_xattr: could not write xattr %s "
|
||||
"for file %s because you're not "
|
||||
"superuser!\n",
|
||||
xattr_list[i].full_name, pathname);
|
||||
EXIT_UNSQUASH_STRICT("write_xattr: to avoid this error message, either"
|
||||
" specify -user-xattrs, -no-xattrs, or run as "
|
||||
"superuser!\n");
|
||||
ERROR("Further error messages of this type are "
|
||||
"suppressed!\n");
|
||||
nonsuper_error = TRUE;
|
||||
failed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
free_xattr(xattr_list, count);
|
||||
|
||||
return !failed;
|
||||
}
|
719
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xattr.c
Normal file
719
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xattr.c
Normal file
|
@ -0,0 +1,719 @@
|
|||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2008, 2009, 2010, 2012, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* xattr.c
|
||||
*/
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_swap.h"
|
||||
#include "mksquashfs.h"
|
||||
#include "xattr.h"
|
||||
#include "error.h"
|
||||
#include "progressbar.h"
|
||||
|
||||
/* compressed xattr table */
|
||||
static char *xattr_table = NULL;
|
||||
static unsigned int xattr_size = 0;
|
||||
|
||||
/* cached uncompressed xattr data */
|
||||
static char *data_cache = NULL;
|
||||
static int cache_bytes = 0, cache_size = 0;
|
||||
|
||||
/* cached uncompressed xattr id table */
|
||||
static struct squashfs_xattr_id *xattr_id_table = NULL;
|
||||
static int xattr_ids = 0;
|
||||
|
||||
/* saved compressed xattr table */
|
||||
unsigned int sxattr_bytes = 0, stotal_xattr_bytes = 0;
|
||||
|
||||
/* saved cached uncompressed xattr data */
|
||||
static char *sdata_cache = NULL;
|
||||
static int scache_bytes = 0;
|
||||
|
||||
/* saved cached uncompressed xattr id table */
|
||||
static int sxattr_ids = 0;
|
||||
|
||||
/* xattr hash table for value duplicate detection */
|
||||
static struct xattr_list *dupl_value[65536];
|
||||
|
||||
/* xattr hash table for id duplicate detection */
|
||||
static struct dupl_id *dupl_id[65536];
|
||||
|
||||
/* file system globals from mksquashfs.c */
|
||||
extern int no_xattrs, noX;
|
||||
extern long long bytes;
|
||||
extern int fd;
|
||||
extern unsigned int xattr_bytes, total_xattr_bytes;
|
||||
|
||||
/* helper functions from mksquashfs.c */
|
||||
extern unsigned short get_checksum(char *, int, unsigned short);
|
||||
extern void write_destination(int, long long, int, void *);
|
||||
extern long long generic_write_table(int, void *, int, void *, int);
|
||||
extern int mangle(char *, char *, int, int, int, int);
|
||||
extern char *pathname(struct dir_ent *);
|
||||
|
||||
/* helper functions and definitions from read_xattrs.c */
|
||||
extern int read_xattrs_from_disk(int, struct squashfs_super_block *, int, long long *);
|
||||
extern struct xattr_list *get_xattr(int, unsigned int *, int *);
|
||||
extern struct prefix prefix_table[];
|
||||
|
||||
|
||||
static int get_prefix(struct xattr_list *xattr, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
xattr->full_name = strdup(name);
|
||||
|
||||
for(i = 0; prefix_table[i].type != -1; i++) {
|
||||
struct prefix *p = &prefix_table[i];
|
||||
if(strncmp(xattr->full_name, p->prefix, strlen(p->prefix)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(prefix_table[i].type != -1) {
|
||||
xattr->name = xattr->full_name + strlen(prefix_table[i].prefix);
|
||||
xattr->size = strlen(xattr->name);
|
||||
}
|
||||
|
||||
return prefix_table[i].type;
|
||||
}
|
||||
|
||||
|
||||
static int read_xattrs_from_system(char *filename, struct xattr_list **xattrs)
|
||||
{
|
||||
ssize_t size, vsize;
|
||||
char *xattr_names, *p;
|
||||
int i;
|
||||
struct xattr_list *xattr_list = NULL;
|
||||
|
||||
while(1) {
|
||||
size = llistxattr(filename, NULL, 0);
|
||||
if(size <= 0) {
|
||||
if(size < 0 && errno != ENOTSUP) {
|
||||
ERROR_START("llistxattr for %s failed in "
|
||||
"read_attrs, because %s", filename,
|
||||
strerror(errno));
|
||||
ERROR_EXIT(". Ignoring");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
xattr_names = malloc(size);
|
||||
if(xattr_names == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
size = llistxattr(filename, xattr_names, size);
|
||||
if(size < 0) {
|
||||
free(xattr_names);
|
||||
if(errno == ERANGE)
|
||||
/* xattr list grew? Try again */
|
||||
continue;
|
||||
else {
|
||||
ERROR_START("llistxattr for %s failed in "
|
||||
"read_attrs, because %s", filename,
|
||||
strerror(errno));
|
||||
ERROR_EXIT(". Ignoring");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0, p = xattr_names; p < xattr_names + size; i++) {
|
||||
struct xattr_list *x = realloc(xattr_list, (i + 1) *
|
||||
sizeof(struct xattr_list));
|
||||
if(x == NULL)
|
||||
MEM_ERROR();
|
||||
xattr_list = x;
|
||||
|
||||
xattr_list[i].type = get_prefix(&xattr_list[i], p);
|
||||
p += strlen(p) + 1;
|
||||
if(xattr_list[i].type == -1) {
|
||||
ERROR("Unrecognised xattr prefix %s\n",
|
||||
xattr_list[i].full_name);
|
||||
free(xattr_list[i].full_name);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
vsize = lgetxattr(filename, xattr_list[i].full_name,
|
||||
NULL, 0);
|
||||
if(vsize < 0) {
|
||||
ERROR_START("lgetxattr failed for %s in "
|
||||
"read_attrs, because %s", filename,
|
||||
strerror(errno));
|
||||
ERROR_EXIT(". Ignoring");
|
||||
free(xattr_list[i].full_name);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
xattr_list[i].value = malloc(vsize);
|
||||
if(xattr_list[i].value == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
vsize = lgetxattr(filename, xattr_list[i].full_name,
|
||||
xattr_list[i].value, vsize);
|
||||
if(vsize < 0) {
|
||||
free(xattr_list[i].value);
|
||||
if(errno == ERANGE)
|
||||
/* xattr grew? Try again */
|
||||
continue;
|
||||
else {
|
||||
ERROR_START("lgetxattr failed for %s "
|
||||
"in read_attrs, because %s",
|
||||
filename, strerror(errno));
|
||||
ERROR_EXIT(". Ignoring");
|
||||
free(xattr_list[i].full_name);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
xattr_list[i].vsize = vsize;
|
||||
|
||||
TRACE("read_xattrs_from_system: filename %s, xattr name %s,"
|
||||
" vsize %d\n", filename, xattr_list[i].full_name,
|
||||
xattr_list[i].vsize);
|
||||
}
|
||||
free(xattr_names);
|
||||
if(i > 0)
|
||||
*xattrs = xattr_list;
|
||||
else
|
||||
free(xattr_list);
|
||||
return i;
|
||||
|
||||
failed:
|
||||
while(--i >= 0) {
|
||||
free(xattr_list[i].full_name);
|
||||
free(xattr_list[i].value);
|
||||
}
|
||||
free(xattr_list);
|
||||
free(xattr_names);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_xattr_size(struct xattr_list *xattr)
|
||||
{
|
||||
int size = sizeof(struct squashfs_xattr_entry) +
|
||||
sizeof(struct squashfs_xattr_val) + xattr->size;
|
||||
|
||||
if(xattr->type & XATTR_VALUE_OOL)
|
||||
size += XATTR_VALUE_OOL_SIZE;
|
||||
else
|
||||
size += xattr->vsize;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static void *get_xattr_space(unsigned int req_size, long long *disk)
|
||||
{
|
||||
int data_space;
|
||||
unsigned short c_byte;
|
||||
|
||||
/*
|
||||
* Move and compress cached uncompressed data into xattr table.
|
||||
*/
|
||||
while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
|
||||
if((xattr_size - xattr_bytes) <
|
||||
((SQUASHFS_METADATA_SIZE << 1)) + 2) {
|
||||
xattr_table = realloc(xattr_table, xattr_size +
|
||||
(SQUASHFS_METADATA_SIZE << 1) + 2);
|
||||
if(xattr_table == NULL)
|
||||
MEM_ERROR();
|
||||
xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
|
||||
}
|
||||
|
||||
c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET,
|
||||
data_cache, SQUASHFS_METADATA_SIZE,
|
||||
SQUASHFS_METADATA_SIZE, noX, 0);
|
||||
TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte);
|
||||
SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1);
|
||||
xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
|
||||
memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
|
||||
cache_bytes - SQUASHFS_METADATA_SIZE);
|
||||
cache_bytes -= SQUASHFS_METADATA_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure there's enough space in the uncompressed data cache
|
||||
*/
|
||||
data_space = cache_size - cache_bytes;
|
||||
if(data_space < req_size) {
|
||||
int realloc_size = req_size - data_space;
|
||||
data_cache = realloc(data_cache, cache_size +
|
||||
realloc_size);
|
||||
if(data_cache == NULL)
|
||||
MEM_ERROR();
|
||||
cache_size += realloc_size;
|
||||
}
|
||||
|
||||
if(disk)
|
||||
*disk = ((long long) xattr_bytes << 16) | cache_bytes;
|
||||
cache_bytes += req_size;
|
||||
return data_cache + cache_bytes - req_size;
|
||||
}
|
||||
|
||||
|
||||
static struct dupl_id *check_id_dupl(struct xattr_list *xattr_list, int xattrs)
|
||||
{
|
||||
struct dupl_id *entry;
|
||||
int i;
|
||||
unsigned short checksum = 0;
|
||||
|
||||
/* compute checksum over all xattrs */
|
||||
for(i = 0; i < xattrs; i++) {
|
||||
struct xattr_list *xattr = &xattr_list[i];
|
||||
|
||||
checksum = get_checksum(xattr->full_name,
|
||||
strlen(xattr->full_name), checksum);
|
||||
checksum = get_checksum(xattr->value,
|
||||
xattr->vsize, checksum);
|
||||
}
|
||||
|
||||
for(entry = dupl_id[checksum]; entry; entry = entry->next) {
|
||||
if (entry->xattrs != xattrs)
|
||||
continue;
|
||||
|
||||
for(i = 0; i < xattrs; i++) {
|
||||
struct xattr_list *xattr = &xattr_list[i];
|
||||
struct xattr_list *dup_xattr = &entry->xattr_list[i];
|
||||
|
||||
if(strcmp(xattr->full_name, dup_xattr->full_name))
|
||||
break;
|
||||
|
||||
if(xattr->vsize != dup_xattr->vsize)
|
||||
break;
|
||||
|
||||
if(memcmp(xattr->value, dup_xattr->value, xattr->vsize))
|
||||
break;
|
||||
}
|
||||
|
||||
if(i == xattrs)
|
||||
break;
|
||||
}
|
||||
|
||||
if(entry == NULL) {
|
||||
/* no duplicate exists */
|
||||
entry = malloc(sizeof(*entry));
|
||||
if(entry == NULL)
|
||||
MEM_ERROR();
|
||||
entry->xattrs = xattrs;
|
||||
entry->xattr_list = xattr_list;
|
||||
entry->xattr_id = SQUASHFS_INVALID_XATTR;
|
||||
entry->next = dupl_id[checksum];
|
||||
dupl_id[checksum] = entry;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static void check_value_dupl(struct xattr_list *xattr)
|
||||
{
|
||||
struct xattr_list *entry;
|
||||
|
||||
if(xattr->vsize < XATTR_VALUE_OOL_SIZE)
|
||||
return;
|
||||
|
||||
/* Check if this is a duplicate of an existing value */
|
||||
xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0);
|
||||
for(entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) {
|
||||
if(entry->vsize != xattr->vsize)
|
||||
continue;
|
||||
|
||||
if(memcmp(entry->value, xattr->value, xattr->vsize) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(entry == NULL) {
|
||||
/*
|
||||
* No duplicate exists, add to hash table, and mark as
|
||||
* requiring writing
|
||||
*/
|
||||
xattr->vnext = dupl_value[xattr->vchecksum];
|
||||
dupl_value[xattr->vchecksum] = xattr;
|
||||
xattr->ool_value = SQUASHFS_INVALID_BLK;
|
||||
} else {
|
||||
/*
|
||||
* Duplicate exists, make type XATTR_VALUE_OOL, and
|
||||
* remember where the duplicate is
|
||||
*/
|
||||
xattr->type |= XATTR_VALUE_OOL;
|
||||
xattr->ool_value = entry->ool_value;
|
||||
/* on appending don't free duplicate values because the
|
||||
* duplicate value already points to the non-duplicate value */
|
||||
if(xattr->value != entry->value) {
|
||||
free(xattr->value);
|
||||
xattr->value = entry->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_xattr_id(int xattrs, struct xattr_list *xattr_list,
|
||||
long long xattr_disk, struct dupl_id *xattr_dupl)
|
||||
{
|
||||
int i, size = 0;
|
||||
struct squashfs_xattr_id *xattr_id;
|
||||
|
||||
xattr_id_table = realloc(xattr_id_table, (xattr_ids + 1) *
|
||||
sizeof(struct squashfs_xattr_id));
|
||||
if(xattr_id_table == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
/* get total uncompressed size of xattr data, needed for stat */
|
||||
for(i = 0; i < xattrs; i++)
|
||||
size += strlen(xattr_list[i].full_name) + 1 +
|
||||
xattr_list[i].vsize;
|
||||
|
||||
xattr_id = &xattr_id_table[xattr_ids];
|
||||
xattr_id->xattr = xattr_disk;
|
||||
xattr_id->count = xattrs;
|
||||
xattr_id->size = size;
|
||||
|
||||
/*
|
||||
* keep track of total uncompressed xattr data, needed for mksquashfs
|
||||
* file system summary
|
||||
*/
|
||||
total_xattr_bytes += size;
|
||||
|
||||
xattr_dupl->xattr_id = xattr_ids ++;
|
||||
return xattr_dupl->xattr_id;
|
||||
}
|
||||
|
||||
|
||||
long long write_xattrs()
|
||||
{
|
||||
unsigned short c_byte;
|
||||
int i, avail_bytes;
|
||||
char *datap = data_cache;
|
||||
long long start_bytes = bytes;
|
||||
struct squashfs_xattr_table header;
|
||||
|
||||
if(xattr_ids == 0)
|
||||
return SQUASHFS_INVALID_BLK;
|
||||
|
||||
/*
|
||||
* Move and compress cached uncompressed data into xattr table.
|
||||
*/
|
||||
while(cache_bytes) {
|
||||
if((xattr_size - xattr_bytes) <
|
||||
((SQUASHFS_METADATA_SIZE << 1)) + 2) {
|
||||
xattr_table = realloc(xattr_table, xattr_size +
|
||||
(SQUASHFS_METADATA_SIZE << 1) + 2);
|
||||
if(xattr_table == NULL)
|
||||
MEM_ERROR();
|
||||
xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
|
||||
}
|
||||
|
||||
avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
|
||||
SQUASHFS_METADATA_SIZE : cache_bytes;
|
||||
c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, datap,
|
||||
avail_bytes, SQUASHFS_METADATA_SIZE, noX, 0);
|
||||
TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte);
|
||||
SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1);
|
||||
xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
|
||||
datap += avail_bytes;
|
||||
cache_bytes -= avail_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write compressed xattr table to file system
|
||||
*/
|
||||
write_destination(fd, bytes, xattr_bytes, xattr_table);
|
||||
bytes += xattr_bytes;
|
||||
|
||||
/*
|
||||
* Swap if necessary the xattr id table
|
||||
*/
|
||||
for(i = 0; i < xattr_ids; i++)
|
||||
SQUASHFS_INSWAP_XATTR_ID(&xattr_id_table[i]);
|
||||
|
||||
header.xattr_ids = xattr_ids;
|
||||
header.xattr_table_start = start_bytes;
|
||||
SQUASHFS_INSWAP_XATTR_TABLE(&header);
|
||||
|
||||
return generic_write_table(xattr_ids * sizeof(struct squashfs_xattr_id),
|
||||
xattr_id_table, sizeof(header), &header, noX);
|
||||
}
|
||||
|
||||
|
||||
int generate_xattrs(int xattrs, struct xattr_list *xattr_list)
|
||||
{
|
||||
int total_size, i;
|
||||
int xattr_value_max;
|
||||
void *xp;
|
||||
long long xattr_disk;
|
||||
struct dupl_id *xattr_dupl;
|
||||
|
||||
/*
|
||||
* check if the file xattrs are a complete duplicate of a pre-existing
|
||||
* id
|
||||
*/
|
||||
xattr_dupl = check_id_dupl(xattr_list, xattrs);
|
||||
if(xattr_dupl->xattr_id != SQUASHFS_INVALID_XATTR)
|
||||
return xattr_dupl->xattr_id;
|
||||
|
||||
/*
|
||||
* Scan the xattr_list deciding which type to assign to each
|
||||
* xattr. The choice is fairly straightforward, and depends on the
|
||||
* size of each xattr name/value and the overall size of the
|
||||
* resultant xattr list stored in the xattr metadata table.
|
||||
*
|
||||
* Choices are whether to store data inline or out of line.
|
||||
*
|
||||
* The overall goal is to optimise xattr scanning and lookup, and
|
||||
* to enable the file system layout to scale from a couple of
|
||||
* small xattr name/values to a large number of large xattr
|
||||
* names/values without affecting performance. While hopefully
|
||||
* enabling the common case of a couple of small xattr name/values
|
||||
* to be stored efficiently
|
||||
*
|
||||
* Code repeatedly scans, doing the following
|
||||
* move xattr data out of line if it exceeds
|
||||
* xattr_value_max. Where xattr_value_max is
|
||||
* initially XATTR_INLINE_MAX. If the final uncompressed
|
||||
* xattr list is larger than XATTR_TARGET_MAX then more
|
||||
* aggressively move xattr data out of line by repeatedly
|
||||
* setting inline threshold to 1/2, then 1/4, 1/8 of
|
||||
* XATTR_INLINE_MAX until target achieved or there's
|
||||
* nothing left to move out of line
|
||||
*/
|
||||
xattr_value_max = XATTR_INLINE_MAX;
|
||||
while(1) {
|
||||
for(total_size = 0, i = 0; i < xattrs; i++) {
|
||||
struct xattr_list *xattr = &xattr_list[i];
|
||||
xattr->type &= XATTR_PREFIX_MASK; /* all inline */
|
||||
if (xattr->vsize > xattr_value_max)
|
||||
xattr->type |= XATTR_VALUE_OOL;
|
||||
|
||||
total_size += get_xattr_size(xattr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the total size of the uncompressed xattr list is <=
|
||||
* XATTR_TARGET_MAX we're done
|
||||
*/
|
||||
if(total_size <= XATTR_TARGET_MAX)
|
||||
break;
|
||||
|
||||
if(xattr_value_max == XATTR_VALUE_OOL_SIZE)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Inline target not yet at minimum and so reduce it, and
|
||||
* try again
|
||||
*/
|
||||
xattr_value_max /= 2;
|
||||
if(xattr_value_max < XATTR_VALUE_OOL_SIZE)
|
||||
xattr_value_max = XATTR_VALUE_OOL_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check xattr values for duplicates
|
||||
*/
|
||||
for(i = 0; i < xattrs; i++) {
|
||||
check_value_dupl(&xattr_list[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add each out of line value to the file system xattr table
|
||||
* if it doesn't already exist as a duplicate
|
||||
*/
|
||||
for(i = 0; i < xattrs; i++) {
|
||||
struct xattr_list *xattr = &xattr_list[i];
|
||||
|
||||
if((xattr->type & XATTR_VALUE_OOL) &&
|
||||
(xattr->ool_value == SQUASHFS_INVALID_BLK)) {
|
||||
struct squashfs_xattr_val val;
|
||||
int size = sizeof(val) + xattr->vsize;
|
||||
xp = get_xattr_space(size, &xattr->ool_value);
|
||||
val.vsize = xattr->vsize;
|
||||
SQUASHFS_SWAP_XATTR_VAL(&val, xp);
|
||||
memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create xattr list and add to file system xattr table
|
||||
*/
|
||||
get_xattr_space(0, &xattr_disk);
|
||||
for(i = 0; i < xattrs; i++) {
|
||||
struct xattr_list *xattr = &xattr_list[i];
|
||||
struct squashfs_xattr_entry entry;
|
||||
struct squashfs_xattr_val val;
|
||||
|
||||
xp = get_xattr_space(sizeof(entry) + xattr->size, NULL);
|
||||
entry.type = xattr->type;
|
||||
entry.size = xattr->size;
|
||||
SQUASHFS_SWAP_XATTR_ENTRY(&entry, xp);
|
||||
memcpy(xp + sizeof(entry), xattr->name, xattr->size);
|
||||
|
||||
if(xattr->type & XATTR_VALUE_OOL) {
|
||||
int size = sizeof(val) + XATTR_VALUE_OOL_SIZE;
|
||||
xp = get_xattr_space(size, NULL);
|
||||
val.vsize = XATTR_VALUE_OOL_SIZE;
|
||||
SQUASHFS_SWAP_XATTR_VAL(&val, xp);
|
||||
SQUASHFS_SWAP_LONG_LONGS(&xattr->ool_value, xp +
|
||||
sizeof(val), 1);
|
||||
} else {
|
||||
int size = sizeof(val) + xattr->vsize;
|
||||
xp = get_xattr_space(size, &xattr->ool_value);
|
||||
val.vsize = xattr->vsize;
|
||||
SQUASHFS_SWAP_XATTR_VAL(&val, xp);
|
||||
memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to xattr id lookup table
|
||||
*/
|
||||
return get_xattr_id(xattrs, xattr_list, xattr_disk, xattr_dupl);
|
||||
}
|
||||
|
||||
|
||||
int read_xattrs(void *d)
|
||||
{
|
||||
struct dir_ent *dir_ent = d;
|
||||
struct inode_info *inode = dir_ent->inode;
|
||||
char *filename = pathname(dir_ent);
|
||||
struct xattr_list *xattr_list;
|
||||
int xattrs;
|
||||
|
||||
if(no_xattrs || IS_PSEUDO(inode) || inode->root_entry)
|
||||
return SQUASHFS_INVALID_XATTR;
|
||||
|
||||
xattrs = read_xattrs_from_system(filename, &xattr_list);
|
||||
if(xattrs == 0)
|
||||
return SQUASHFS_INVALID_XATTR;
|
||||
|
||||
return generate_xattrs(xattrs, xattr_list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add the existing xattr ids and xattr metadata in the file system being
|
||||
* appended to, to the in-memory xattr cache. This allows duplicate checking to
|
||||
* take place against the xattrs already in the file system being appended to,
|
||||
* and ensures the pre-existing xattrs are written out along with any new xattrs
|
||||
*/
|
||||
int get_xattrs(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
int ids, res, i, id;
|
||||
unsigned int count;
|
||||
|
||||
TRACE("get_xattrs\n");
|
||||
|
||||
res = read_xattrs_from_disk(fd, sBlk, FALSE, NULL);
|
||||
if(res == SQUASHFS_INVALID_BLK || res == 0)
|
||||
goto done;
|
||||
ids = res;
|
||||
|
||||
/*
|
||||
* for each xattr id read and construct its list of xattr
|
||||
* name:value pairs, and add them to the in-memory xattr cache
|
||||
*/
|
||||
for(i = 0; i < ids; i++) {
|
||||
struct xattr_list *xattr_list = get_xattr(i, &count, &res);
|
||||
if(res) {
|
||||
free_xattr(xattr_list, count);
|
||||
return FALSE;
|
||||
}
|
||||
id = generate_xattrs(count, xattr_list);
|
||||
|
||||
/*
|
||||
* Sanity check, the new xattr id should be the same as the
|
||||
* xattr id in the original file system
|
||||
*/
|
||||
if(id != i) {
|
||||
ERROR("BUG, different xattr_id in get_xattrs\n");
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save current state of xattrs, needed for restoring state in the event of an
|
||||
* abort in appending
|
||||
*/
|
||||
void save_xattrs()
|
||||
{
|
||||
/* save the current state of the compressed xattr data */
|
||||
sxattr_bytes = xattr_bytes;
|
||||
stotal_xattr_bytes = total_xattr_bytes;
|
||||
|
||||
/*
|
||||
* save the current state of the cached uncompressed xattr data.
|
||||
* Note we have to save the contents of the data cache because future
|
||||
* operations will delete the current contents
|
||||
*/
|
||||
sdata_cache = malloc(cache_bytes);
|
||||
if(sdata_cache == NULL)
|
||||
MEM_ERROR();
|
||||
|
||||
memcpy(sdata_cache, data_cache, cache_bytes);
|
||||
scache_bytes = cache_bytes;
|
||||
|
||||
/* save the current state of the xattr id table */
|
||||
sxattr_ids = xattr_ids;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Restore xattrs in the event of an abort in appending
|
||||
*/
|
||||
void restore_xattrs()
|
||||
{
|
||||
/* restore the state of the compressed xattr data */
|
||||
xattr_bytes = sxattr_bytes;
|
||||
total_xattr_bytes = stotal_xattr_bytes;
|
||||
|
||||
/* restore the state of the uncomoressed xattr data */
|
||||
memcpy(data_cache, sdata_cache, scache_bytes);
|
||||
cache_bytes = scache_bytes;
|
||||
|
||||
/* restore the state of the xattr id table */
|
||||
xattr_ids = sxattr_ids;
|
||||
}
|
151
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xattr.h
Normal file
151
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xattr.h
Normal file
|
@ -0,0 +1,151 @@
|
|||
#ifndef XATTR_H
|
||||
#define XATTR_H
|
||||
/*
|
||||
* Create a squashfs filesystem. This is a highly compressed read only
|
||||
* filesystem.
|
||||
*
|
||||
* Copyright (c) 2010, 2012, 2013, 2014, 2019
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* xattr.h
|
||||
*/
|
||||
|
||||
#define XATTR_VALUE_OOL SQUASHFS_XATTR_VALUE_OOL
|
||||
#define XATTR_PREFIX_MASK SQUASHFS_XATTR_PREFIX_MASK
|
||||
|
||||
#define XATTR_VALUE_OOL_SIZE sizeof(long long)
|
||||
|
||||
/* maximum size of xattr value data that will be inlined */
|
||||
#define XATTR_INLINE_MAX 128
|
||||
|
||||
/* the target size of an inode's xattr name:value list. If it
|
||||
* exceeds this, then xattr value data will be successively out of lined
|
||||
* until it meets the target */
|
||||
#define XATTR_TARGET_MAX 65536
|
||||
|
||||
#define IS_XATTR(a) (a != SQUASHFS_INVALID_XATTR)
|
||||
|
||||
struct xattr_list {
|
||||
char *name;
|
||||
char *full_name;
|
||||
int size;
|
||||
int vsize;
|
||||
void *value;
|
||||
int type;
|
||||
long long ool_value;
|
||||
unsigned short vchecksum;
|
||||
struct xattr_list *vnext;
|
||||
};
|
||||
|
||||
struct dupl_id {
|
||||
struct xattr_list *xattr_list;
|
||||
int xattrs;
|
||||
int xattr_id;
|
||||
struct dupl_id *next;
|
||||
};
|
||||
|
||||
struct prefix {
|
||||
char *prefix;
|
||||
int type;
|
||||
};
|
||||
|
||||
extern int generate_xattrs(int, struct xattr_list *);
|
||||
|
||||
#ifdef XATTR_SUPPORT
|
||||
extern int get_xattrs(int, struct squashfs_super_block *);
|
||||
extern int read_xattrs(void *);
|
||||
extern long long write_xattrs();
|
||||
extern void save_xattrs();
|
||||
extern void restore_xattrs();
|
||||
extern unsigned int xattr_bytes, total_xattr_bytes;
|
||||
extern int write_xattr(char *, unsigned int);
|
||||
extern int read_xattrs_from_disk(int, struct squashfs_super_block *, int, long long *);
|
||||
extern struct xattr_list *get_xattr(int, unsigned int *, int *);
|
||||
extern void free_xattr(struct xattr_list *, int);
|
||||
#else
|
||||
static inline int get_xattrs(int fd, struct squashfs_super_block *sBlk)
|
||||
{
|
||||
if(sBlk->xattr_id_table_start != SQUASHFS_INVALID_BLK) {
|
||||
fprintf(stderr, "Xattrs in filesystem! These are not "
|
||||
"supported on this version of Squashfs\n");
|
||||
return 0;
|
||||
} else
|
||||
return SQUASHFS_INVALID_BLK;
|
||||
}
|
||||
|
||||
|
||||
static inline int read_xattrs(void *dir_ent)
|
||||
{
|
||||
return SQUASHFS_INVALID_XATTR;
|
||||
}
|
||||
|
||||
|
||||
static inline long long write_xattrs()
|
||||
{
|
||||
return SQUASHFS_INVALID_BLK;
|
||||
}
|
||||
|
||||
|
||||
static inline void save_xattrs()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static inline void restore_xattrs()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static inline int write_xattr(char *pathname, unsigned int xattr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk, int flag, long long *table_start)
|
||||
{
|
||||
if(sBlk->xattr_id_table_start != SQUASHFS_INVALID_BLK) {
|
||||
fprintf(stderr, "Xattrs in filesystem! These are not "
|
||||
"supported on this version of Squashfs\n");
|
||||
return 0;
|
||||
} else
|
||||
return SQUASHFS_INVALID_BLK;
|
||||
}
|
||||
|
||||
|
||||
static inline struct xattr_list *get_xattr(int i, unsigned int *count, int j)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XATTR_SUPPORT
|
||||
#ifdef XATTR_DEFAULT
|
||||
#define NOXOPT_STR
|
||||
#define XOPT_STR " (default)"
|
||||
#define XATTR_DEF 0
|
||||
#else
|
||||
#define NOXOPT_STR " (default)"
|
||||
#define XOPT_STR
|
||||
#define XATTR_DEF 1
|
||||
#endif
|
||||
#else
|
||||
#define NOXOPT_STR " (default)"
|
||||
#define XOPT_STR " (unsupported)"
|
||||
#define XATTR_DEF 1
|
||||
#endif
|
||||
#endif
|
540
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xz_wrapper.c
Normal file
540
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xz_wrapper.c
Normal file
|
@ -0,0 +1,540 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2011, 2012, 2013
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* xz_wrapper.c
|
||||
*
|
||||
* Support for XZ (LZMA2) compression using XZ Utils liblzma
|
||||
* http://tukaani.org/xz/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <lzma.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "xz_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
static struct bcj bcj[] = {
|
||||
{ "x86", LZMA_FILTER_X86, 0 },
|
||||
{ "powerpc", LZMA_FILTER_POWERPC, 0 },
|
||||
{ "ia64", LZMA_FILTER_IA64, 0 },
|
||||
{ "arm", LZMA_FILTER_ARM, 0 },
|
||||
{ "armthumb", LZMA_FILTER_ARMTHUMB, 0 },
|
||||
{ "sparc", LZMA_FILTER_SPARC, 0 },
|
||||
{ NULL, LZMA_VLI_UNKNOWN, 0 }
|
||||
};
|
||||
|
||||
static int filter_count = 1;
|
||||
static int dictionary_size = 0;
|
||||
static float dictionary_percent = 0;
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* Two specific options are supported:
|
||||
* -Xbcj
|
||||
* -Xdict-size
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The xz_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int xz_options(char *argv[], int argc)
|
||||
{
|
||||
int i;
|
||||
char *name;
|
||||
|
||||
if(strcmp(argv[0], "-Xbcj") == 0) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "xz: -Xbcj missing filter\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
name = argv[1];
|
||||
while(name[0] != '\0') {
|
||||
for(i = 0; bcj[i].name; i++) {
|
||||
int n = strlen(bcj[i].name);
|
||||
if((strncmp(name, bcj[i].name, n) == 0) &&
|
||||
(name[n] == '\0' ||
|
||||
name[n] == ',')) {
|
||||
if(bcj[i].selected == 0) {
|
||||
bcj[i].selected = 1;
|
||||
filter_count++;
|
||||
}
|
||||
name += name[n] == ',' ? n + 1 : n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bcj[i].name == NULL) {
|
||||
fprintf(stderr, "xz: -Xbcj unrecognised "
|
||||
"filter\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if(strcmp(argv[0], "-Xdict-size") == 0) {
|
||||
char *b;
|
||||
float size;
|
||||
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
size = strtof(argv[1], &b);
|
||||
if(*b == '%') {
|
||||
if(size <= 0 || size > 100) {
|
||||
fprintf(stderr, "xz: -Xdict-size percentage "
|
||||
"should be 0 < dict-size <= 100\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
dictionary_percent = size;
|
||||
dictionary_size = 0;
|
||||
} else {
|
||||
if((float) ((int) size) != size) {
|
||||
fprintf(stderr, "xz: -Xdict-size can't be "
|
||||
"fractional unless a percentage of the"
|
||||
" block size\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
dictionary_percent = 0;
|
||||
dictionary_size = (int) size;
|
||||
|
||||
if(*b == 'k' || *b == 'K')
|
||||
dictionary_size *= 1024;
|
||||
else if(*b == 'm' || *b == 'M')
|
||||
dictionary_size *= 1024 * 1024;
|
||||
else if(*b != '\0') {
|
||||
fprintf(stderr, "xz: -Xdict-size invalid "
|
||||
"dict-size\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
failed:
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after all options have been parsed.
|
||||
* It is used to do post-processing on the compressor options using
|
||||
* values that were not expected to be known at option parse time.
|
||||
*
|
||||
* In this case block_size may not be known until after -Xdict-size has
|
||||
* been processed (in the case where -b is specified after -Xdict-size)
|
||||
*
|
||||
* This function returns 0 on successful post processing, or
|
||||
* -1 on error
|
||||
*/
|
||||
static int xz_options_post(int block_size)
|
||||
{
|
||||
/*
|
||||
* if -Xdict-size has been specified use this to compute the datablock
|
||||
* dictionary size
|
||||
*/
|
||||
if(dictionary_size || dictionary_percent) {
|
||||
int n;
|
||||
|
||||
if(dictionary_size) {
|
||||
if(dictionary_size > block_size) {
|
||||
fprintf(stderr, "xz: -Xdict-size is larger than"
|
||||
" block_size\n");
|
||||
goto failed;
|
||||
}
|
||||
} else
|
||||
dictionary_size = block_size * dictionary_percent / 100;
|
||||
|
||||
if(dictionary_size < 8192) {
|
||||
fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
|
||||
"or larger\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* dictionary_size must be storable in xz header as either
|
||||
* 2^n or as 2^n+2^(n+1)
|
||||
*/
|
||||
n = ffs(dictionary_size) - 1;
|
||||
if(dictionary_size != (1 << n) &&
|
||||
dictionary_size != ((1 << n) + (1 << (n + 1)))) {
|
||||
fprintf(stderr, "xz: -Xdict-size is an unsupported "
|
||||
"value, dict-size must be storable in xz "
|
||||
"header\n");
|
||||
fprintf(stderr, "as either 2^n or as 2^n+2^(n+1). "
|
||||
"Example dict-sizes are 75%%, 50%%, 37.5%%, "
|
||||
"25%%,\n");
|
||||
fprintf(stderr, "or 32K, 16K, 8K etc.\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
} else
|
||||
/* No -Xdict-size specified, use defaults */
|
||||
dictionary_size = block_size;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options
|
||||
*/
|
||||
static void *xz_dump_options(int block_size, int *size)
|
||||
{
|
||||
static struct comp_opts comp_opts;
|
||||
int flags = 0, i;
|
||||
|
||||
/*
|
||||
* don't store compressor specific options in file system if the
|
||||
* default options are being used - no compressor options in the
|
||||
* file system means the default options are always assumed
|
||||
*
|
||||
* Defaults are:
|
||||
* metadata dictionary size: SQUASHFS_METADATA_SIZE
|
||||
* datablock dictionary size: block_size
|
||||
* 1 filter
|
||||
*/
|
||||
if(dictionary_size == block_size && filter_count == 1)
|
||||
return NULL;
|
||||
|
||||
for(i = 0; bcj[i].name; i++)
|
||||
flags |= bcj[i].selected << i;
|
||||
|
||||
comp_opts.dictionary_size = dictionary_size;
|
||||
comp_opts.flags = flags;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
||||
|
||||
*size = sizeof(comp_opts);
|
||||
return &comp_opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int xz_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct comp_opts *comp_opts = buffer;
|
||||
int flags, i, n;
|
||||
|
||||
if(size == 0) {
|
||||
/* set defaults */
|
||||
dictionary_size = block_size;
|
||||
flags = 0;
|
||||
} else {
|
||||
/* check passed comp opts struct is of the correct length */
|
||||
if(size != sizeof(struct comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
dictionary_size = comp_opts->dictionary_size;
|
||||
flags = comp_opts->flags;
|
||||
|
||||
/*
|
||||
* check that the dictionary size seems correct - the dictionary
|
||||
* size should 2^n or 2^n+2^(n+1)
|
||||
*/
|
||||
n = ffs(dictionary_size) - 1;
|
||||
if(dictionary_size != (1 << n) &&
|
||||
dictionary_size != ((1 << n) + (1 << (n + 1))))
|
||||
goto failed;
|
||||
}
|
||||
|
||||
filter_count = 1;
|
||||
for(i = 0; bcj[i].name; i++) {
|
||||
if((flags >> i) & 1) {
|
||||
bcj[i].selected = 1;
|
||||
filter_count ++;
|
||||
} else
|
||||
bcj[i].selected = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "xz: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void xz_display_options(void *buffer, int size)
|
||||
{
|
||||
struct comp_opts *comp_opts = buffer;
|
||||
int dictionary_size, flags, printed;
|
||||
int i, n;
|
||||
|
||||
/* check passed comp opts struct is of the correct length */
|
||||
if(size != sizeof(struct comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
dictionary_size = comp_opts->dictionary_size;
|
||||
flags = comp_opts->flags;
|
||||
|
||||
/*
|
||||
* check that the dictionary size seems correct - the dictionary
|
||||
* size should 2^n or 2^n+2^(n+1)
|
||||
*/
|
||||
n = ffs(dictionary_size) - 1;
|
||||
if(dictionary_size != (1 << n) &&
|
||||
dictionary_size != ((1 << n) + (1 << (n + 1))))
|
||||
goto failed;
|
||||
|
||||
printf("\tDictionary size %d\n", dictionary_size);
|
||||
|
||||
printed = 0;
|
||||
for(i = 0; bcj[i].name; i++) {
|
||||
if((flags >> i) & 1) {
|
||||
if(printed)
|
||||
printf(", ");
|
||||
else
|
||||
printf("\tFilters selected: ");
|
||||
printf("%s", bcj[i].name);
|
||||
printed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!printed)
|
||||
printf("\tNo filters specified\n");
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "xz: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to initialise the
|
||||
* compressor, before compress() is called.
|
||||
*
|
||||
* This function returns 0 on success, and
|
||||
* -1 on error
|
||||
*/
|
||||
static int xz_init(void **strm, int block_size, int datablock)
|
||||
{
|
||||
int i, j, filters = datablock ? filter_count : 1;
|
||||
struct filter *filter = malloc(filters * sizeof(struct filter));
|
||||
struct xz_stream *stream;
|
||||
|
||||
if(filter == NULL)
|
||||
goto failed;
|
||||
|
||||
stream = *strm = malloc(sizeof(struct xz_stream));
|
||||
if(stream == NULL)
|
||||
goto failed2;
|
||||
|
||||
stream->filter = filter;
|
||||
stream->filters = filters;
|
||||
|
||||
memset(filter, 0, filters * sizeof(struct filter));
|
||||
|
||||
stream->dictionary_size = datablock ? dictionary_size :
|
||||
SQUASHFS_METADATA_SIZE;
|
||||
|
||||
filter[0].filter[0].id = LZMA_FILTER_LZMA2;
|
||||
filter[0].filter[0].options = &stream->opt;
|
||||
filter[0].filter[1].id = LZMA_VLI_UNKNOWN;
|
||||
|
||||
for(i = 0, j = 1; datablock && bcj[i].name; i++) {
|
||||
if(bcj[i].selected) {
|
||||
filter[j].buffer = malloc(block_size);
|
||||
if(filter[j].buffer == NULL)
|
||||
goto failed3;
|
||||
filter[j].filter[0].id = bcj[i].id;
|
||||
filter[j].filter[1].id = LZMA_FILTER_LZMA2;
|
||||
filter[j].filter[1].options = &stream->opt;
|
||||
filter[j].filter[2].id = LZMA_VLI_UNKNOWN;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed3:
|
||||
for(i = 1; i < filters; i++)
|
||||
free(filter[i].buffer);
|
||||
free(stream);
|
||||
|
||||
failed2:
|
||||
free(filter);
|
||||
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int xz_compress(void *strm, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
int i;
|
||||
lzma_ret res = 0;
|
||||
struct xz_stream *stream = strm;
|
||||
struct filter *selected = NULL;
|
||||
|
||||
stream->filter[0].buffer = dest;
|
||||
|
||||
for(i = 0; i < stream->filters; i++) {
|
||||
struct filter *filter = &stream->filter[i];
|
||||
|
||||
if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
|
||||
goto failed;
|
||||
|
||||
stream->opt.dict_size = stream->dictionary_size;
|
||||
|
||||
filter->length = 0;
|
||||
res = lzma_stream_buffer_encode(filter->filter,
|
||||
LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
|
||||
&filter->length, block_size);
|
||||
|
||||
if(res == LZMA_OK) {
|
||||
if(!selected || selected->length > filter->length)
|
||||
selected = filter;
|
||||
} else if(res != LZMA_BUF_ERROR)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if(!selected)
|
||||
/*
|
||||
* Output buffer overflow. Return out of buffer space
|
||||
*/
|
||||
return 0;
|
||||
|
||||
if(selected->buffer != dest)
|
||||
memcpy(dest, selected->buffer, selected->length);
|
||||
|
||||
return (int) selected->length;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* All other errors return failure, with the compressor
|
||||
* specific error code in *error
|
||||
*/
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int xz_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
size_t src_pos = 0;
|
||||
size_t dest_pos = 0;
|
||||
uint64_t memlimit = MEMLIMIT;
|
||||
|
||||
lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL,
|
||||
src, &src_pos, size, dest, &dest_pos, outsize);
|
||||
|
||||
if(res == LZMA_OK && size == (int) src_pos)
|
||||
return (int) dest_pos;
|
||||
else {
|
||||
*error = res;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void xz_usage()
|
||||
{
|
||||
fprintf(stderr, "\t -Xbcj filter1,filter2,...,filterN\n");
|
||||
fprintf(stderr, "\t\tCompress using filter1,filter2,...,filterN in");
|
||||
fprintf(stderr, " turn\n\t\t(in addition to no filter), and choose");
|
||||
fprintf(stderr, " the best compression.\n");
|
||||
fprintf(stderr, "\t\tAvailable filters: x86, arm, armthumb,");
|
||||
fprintf(stderr, " powerpc, sparc, ia64\n");
|
||||
fprintf(stderr, "\t -Xdict-size <dict-size>\n");
|
||||
fprintf(stderr, "\t\tUse <dict-size> as the XZ dictionary size. The");
|
||||
fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
|
||||
fprintf(stderr, " percentage of the block size, or as an\n\t\t");
|
||||
fprintf(stderr, "absolute value. The dictionary size must be less");
|
||||
fprintf(stderr, " than or equal\n\t\tto the block size and 8192 bytes");
|
||||
fprintf(stderr, " or larger. It must also be\n\t\tstorable in the xz");
|
||||
fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
|
||||
fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
|
||||
fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
|
||||
}
|
||||
|
||||
|
||||
struct compressor xz_comp_ops = {
|
||||
.init = xz_init,
|
||||
.compress = xz_compress,
|
||||
.uncompress = xz_uncompress,
|
||||
.options = xz_options,
|
||||
.options_post = xz_options_post,
|
||||
.dump_options = xz_dump_options,
|
||||
.extract_options = xz_extract_options,
|
||||
.display_options = xz_display_options,
|
||||
.usage = xz_usage,
|
||||
.id = XZ_COMPRESSION,
|
||||
.name = "xz",
|
||||
.supported = 1
|
||||
};
|
71
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xz_wrapper.h
Normal file
71
SQUASHFS/squashfs-tools-4.4/squashfs-tools/xz_wrapper.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
#ifndef XZ_WRAPPER_H
|
||||
#define XZ_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2010
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* xz_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->dictionary_size = inswap_le32((s)->dictionary_size); \
|
||||
(s)->flags = inswap_le32((s)->flags); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
#define MEMLIMIT (32 * 1024 * 1024)
|
||||
|
||||
struct bcj {
|
||||
char *name;
|
||||
lzma_vli id;
|
||||
int selected;
|
||||
};
|
||||
|
||||
struct filter {
|
||||
void *buffer;
|
||||
lzma_filter filter[3];
|
||||
size_t length;
|
||||
};
|
||||
|
||||
struct xz_stream {
|
||||
struct filter *filter;
|
||||
int filters;
|
||||
int dictionary_size;
|
||||
lzma_options_lzma opt;
|
||||
};
|
||||
|
||||
struct comp_opts {
|
||||
int dictionary_size;
|
||||
int flags;
|
||||
};
|
||||
#endif
|
199
SQUASHFS/squashfs-tools-4.4/squashfs-tools/zstd_wrapper.c
Normal file
199
SQUASHFS/squashfs-tools-4.4/squashfs-tools/zstd_wrapper.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2017
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* zstd_wrapper.c
|
||||
*
|
||||
* Support for ZSTD compression http://zstd.net
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <zstd.h>
|
||||
#include <zstd_errors.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "zstd_wrapper.h"
|
||||
#include "compressor.h"
|
||||
|
||||
static int compression_level = ZSTD_DEFAULT_COMPRESSION_LEVEL;
|
||||
|
||||
/*
|
||||
* This function is called by the options parsing code in mksquashfs.c
|
||||
* to parse any -X compressor option.
|
||||
*
|
||||
* This function returns:
|
||||
* >=0 (number of additional args parsed) on success
|
||||
* -1 if the option was unrecognised, or
|
||||
* -2 if the option was recognised, but otherwise bad in
|
||||
* some way (e.g. invalid parameter)
|
||||
*
|
||||
* Note: this function sets internal compressor state, but does not
|
||||
* pass back the results of the parsing other than success/failure.
|
||||
* The zstd_dump_options() function is called later to get the options in
|
||||
* a format suitable for writing to the filesystem.
|
||||
*/
|
||||
static int zstd_options(char *argv[], int argc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to dump the parsed
|
||||
* compressor options in a format suitable for writing to the
|
||||
* compressor options field in the filesystem (stored immediately
|
||||
* after the superblock).
|
||||
*
|
||||
* This function returns a pointer to the compression options structure
|
||||
* to be stored (and the size), or NULL if there are no compression
|
||||
* options.
|
||||
*/
|
||||
static void *zstd_dump_options(int block_size, int *size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a helper specifically for the append mode of
|
||||
* mksquashfs. Its purpose is to set the internal compressor state
|
||||
* to the stored compressor options in the passed compressor options
|
||||
* structure.
|
||||
*
|
||||
* In effect this function sets up the compressor options
|
||||
* to the same state they were when the filesystem was originally
|
||||
* generated, this is to ensure on appending, the compressor uses
|
||||
* the same compression options that were used to generate the
|
||||
* original filesystem.
|
||||
*
|
||||
* Note, even if there are no compressor options, this function is still
|
||||
* called with an empty compressor structure (size == 0), to explicitly
|
||||
* set the default options, this is to ensure any user supplied
|
||||
* -X options on the appending mksquashfs command line are over-ridden.
|
||||
*
|
||||
* This function returns 0 on sucessful extraction of options, and -1 on error.
|
||||
*/
|
||||
static int zstd_extract_options(int block_size, void *buffer, int size)
|
||||
{
|
||||
struct zstd_comp_opts *comp_opts = buffer;
|
||||
|
||||
if (size == 0) {
|
||||
/* Set default values */
|
||||
compression_level = ZSTD_DEFAULT_COMPRESSION_LEVEL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if (size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
if (comp_opts->compression_level < 1) {
|
||||
fprintf(stderr, "zstd: bad compression level in compression "
|
||||
"options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
compression_level = comp_opts->compression_level;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "zstd: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void zstd_display_options(void *buffer, int size)
|
||||
{
|
||||
struct zstd_comp_opts *comp_opts = buffer;
|
||||
|
||||
/* we expect a comp_opts structure of sufficient size to be present */
|
||||
if (size < sizeof(*comp_opts))
|
||||
goto failed;
|
||||
|
||||
SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
||||
|
||||
if (comp_opts->compression_level < 1) {
|
||||
fprintf(stderr, "zstd: bad compression level in compression "
|
||||
"options structure\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
printf("\tcompression-level %d\n", comp_opts->compression_level);
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
fprintf(stderr, "zstd: error reading stored compressor options from "
|
||||
"filesystem!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by mksquashfs to initialise the
|
||||
* compressor, before compress() is called.
|
||||
*
|
||||
* This function returns 0 on success, and -1 on error.
|
||||
*/
|
||||
static int zstd_init(void **strm, int block_size, int datablock)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zstd_compress(void *strm, void *dest, void *src, int size,
|
||||
int block_size, int *error)
|
||||
{
|
||||
(void)strm;
|
||||
(void)dest;
|
||||
(void)src;
|
||||
(void)size;
|
||||
(void)block_size;
|
||||
(void)error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zstd_uncompress(void *dest, void *src, int size, int outsize,
|
||||
int *error)
|
||||
{
|
||||
const size_t res = ZSTD_decompress(dest, outsize, src, size);
|
||||
|
||||
if (ZSTD_isError(res)) {
|
||||
fprintf(stderr, "\t%d %d\n", outsize, size);
|
||||
|
||||
*error = (int)ZSTD_getErrorCode(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)res;
|
||||
}
|
||||
|
||||
static void zstd_usage(void)
|
||||
{
|
||||
fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
|
||||
}
|
||||
|
||||
struct compressor zstd_comp_ops = {
|
||||
.init = zstd_init,
|
||||
.compress = zstd_compress,
|
||||
.uncompress = zstd_uncompress,
|
||||
.options = zstd_options,
|
||||
.dump_options = zstd_dump_options,
|
||||
.extract_options = zstd_extract_options,
|
||||
.display_options = zstd_display_options,
|
||||
.usage = zstd_usage,
|
||||
.id = ZSTD_COMPRESSION,
|
||||
.name = "zstd",
|
||||
.supported = 1
|
||||
};
|
48
SQUASHFS/squashfs-tools-4.4/squashfs-tools/zstd_wrapper.h
Normal file
48
SQUASHFS/squashfs-tools-4.4/squashfs-tools/zstd_wrapper.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef ZSTD_WRAPPER_H
|
||||
#define ZSTD_WRAPPER_H
|
||||
/*
|
||||
* Squashfs
|
||||
*
|
||||
* Copyright (c) 2017
|
||||
* Phillip Lougher <phillip@squashfs.org.uk>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* zstd_wrapper.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
extern unsigned int inswap_le16(unsigned short);
|
||||
extern unsigned int inswap_le32(unsigned int);
|
||||
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
|
||||
(s)->compression_level = inswap_le32((s)->compression_level); \
|
||||
}
|
||||
#else
|
||||
#define SQUASHFS_INSWAP_COMP_OPTS(s)
|
||||
#endif
|
||||
|
||||
/* Default compression */
|
||||
#define ZSTD_DEFAULT_COMPRESSION_LEVEL 15
|
||||
|
||||
struct zstd_comp_opts {
|
||||
int compression_level;
|
||||
};
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue